(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory(require("echarts"));
	else if(typeof define === 'function' && define.amd)
		define(["echarts"], factory);
	else if(typeof exports === 'object')
		exports["echarts-gl"] = factory(require("echarts"));
	else
		root["echarts-gl"] = factory(root["echarts"]);
})(self, function(__WEBPACK_EXTERNAL_MODULE_echarts_lib_echarts__) {
return /******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	var __webpack_modules__ = ({

/***/ "./src/export/all.js":
/*!*****************************************!*\
  !*** ./src/export/all.js + 360 modules ***!
  \*****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);

// EXTERNAL MODULE: external "echarts"
var external_echarts_ = __webpack_require__("echarts/lib/echarts");
;// CONCATENATED MODULE: ./node_modules/claygl/src/core/mixin/extend.js
/**
 * Extend a sub class from base class
 * @param {object|Function} makeDefaultOpt default option of this sub class, method of the sub can use this.xxx to access this option
 * @param {Function} [initialize] Initialize after the sub class is instantiated
 * @param {Object} [proto] Prototype methods/properties of the sub class
 * @memberOf clay.core.mixin.extend
 * @return {Function}
 */
function derive(makeDefaultOpt, initialize/*optional*/, proto/*optional*/) {

    if (typeof initialize == 'object') {
        proto = initialize;
        initialize = null;
    }

    var _super = this;

    var propList;
    if (!(makeDefaultOpt instanceof Function)) {
        // Optimize the property iterate if it have been fixed
        propList = [];
        for (var propName in makeDefaultOpt) {
            if (makeDefaultOpt.hasOwnProperty(propName)) {
                propList.push(propName);
            }
        }
    }

    var sub = function(options) {

        // call super constructor
        _super.apply(this, arguments);

        if (makeDefaultOpt instanceof Function) {
            // Invoke makeDefaultOpt each time if it is a function, So we can make sure each
            // property in the object will not be shared by mutiple instances
            extend(this, makeDefaultOpt.call(this, options));
        }
        else {
            extendWithPropList(this, makeDefaultOpt, propList);
        }

        if (this.constructor === sub) {
            // Initialize function will be called in the order of inherit
            var initializers = sub.__initializers__;
            for (var i = 0; i < initializers.length; i++) {
                initializers[i].apply(this, arguments);
            }
        }
    };
    // save super constructor
    sub.__super__ = _super;
    // Initialize function will be called after all the super constructor is called
    if (!_super.__initializers__) {
        sub.__initializers__ = [];
    } else {
        sub.__initializers__ = _super.__initializers__.slice();
    }
    if (initialize) {
        sub.__initializers__.push(initialize);
    }

    var Ctor = function() {};
    Ctor.prototype = _super.prototype;
    sub.prototype = new Ctor();
    sub.prototype.constructor = sub;
    extend(sub.prototype, proto);

    // extend the derive method as a static method;
    sub.extend = _super.extend;

    // DEPCRATED
    sub.derive = _super.extend;

    return sub;
}

function extend(target, source) {
    if (!source) {
        return;
    }
    for (var name in source) {
        if (source.hasOwnProperty(name)) {
            target[name] = source[name];
        }
    }
}

function extendWithPropList(target, source, propList) {
    for (var i = 0; i < propList.length; i++) {
        var propName = propList[i];
        target[propName] = source[propName];
    }
}

/**
 * @alias clay.core.mixin.extend
 * @mixin
 */
/* harmony default export */ const mixin_extend = ({

    extend: derive,

    // DEPCRATED
    derive: derive
});

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/mixin/notifier.js
function Handler(action, context) {
    this.action = action;
    this.context = context;
}
/**
 * @mixin
 * @alias clay.core.mixin.notifier
 */
var notifier = {
    /**
     * Trigger event
     * @param  {string} name
     */
    trigger: function(name) {
        if (!this.hasOwnProperty('__handlers__')) {
            return;
        }
        if (!this.__handlers__.hasOwnProperty(name)) {
            return;
        }

        var hdls = this.__handlers__[name];
        var l = hdls.length, i = -1, args = arguments;
        // Optimize advise from backbone
        switch (args.length) {
            case 1:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context);
                }
                return;
            case 2:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1]);
                }
                return;
            case 3:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2]);
                }
                return;
            case 4:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2], args[3]);
                }
                return;
            case 5:
                while (++i < l) {
                    hdls[i].action.call(hdls[i].context, args[1], args[2], args[3], args[4]);
                }
                return;
            default:
                while (++i < l) {
                    hdls[i].action.apply(hdls[i].context, Array.prototype.slice.call(args, 1));
                }
                return;
        }
    },
    /**
     * Register event handler
     * @param  {string} name
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    on: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        var handlers = this.__handlers__ || (this.__handlers__={});
        if (!handlers[name]) {
            handlers[name] = [];
        }
        else {
            if (this.has(name, action)) {
                return;
            }
        }
        var handler = new Handler(action, context || this);
        handlers[name].push(handler);

        return this;
    },

    /**
     * Register event, event will only be triggered once and then removed
     * @param  {string} name
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    once: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        var self = this;
        function wrapper() {
            self.off(name, wrapper);
            action.apply(this, arguments);
        }
        return this.on(name, wrapper, context);
    },

    /**
     * Alias of once('before' + name)
     * @param  {string} name
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    before: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        name = 'before' + name;
        return this.on(name, action, context);
    },

    /**
     * Alias of once('after' + name)
     * @param  {string} name
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    after: function(name, action, context) {
        if (!name || !action) {
            return;
        }
        name = 'after' + name;
        return this.on(name, action, context);
    },

    /**
     * Alias of on('success')
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    success: function(action, context) {
        return this.once('success', action, context);
    },

    /**
     * Alias of on('error')
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    error: function(action, context) {
        return this.once('error', action, context);
    },

    /**
     * Remove event listener
     * @param  {Function} action
     * @param  {Object} [context]
     * @chainable
     */
    off: function(name, action) {

        var handlers = this.__handlers__ || (this.__handlers__={});

        if (!action) {
            handlers[name] = [];
            return;
        }
        if (handlers[name]) {
            var hdls = handlers[name];
            var retains = [];
            for (var i = 0; i < hdls.length; i++) {
                if (action && hdls[i].action !== action) {
                    retains.push(hdls[i]);
                }
            }
            handlers[name] = retains;
        }

        return this;
    },

    /**
     * If registered the event handler
     * @param  {string}  name
     * @param  {Function}  action
     * @return {boolean}
     */
    has: function(name, action) {
        var handlers = this.__handlers__;

        if (! handlers ||
            ! handlers[name]) {
            return false;
        }
        var hdls = handlers[name];
        for (var i = 0; i < hdls.length; i++) {
            if (hdls[i].action === action) {
                return true;
            }
        }
    }
};

/* harmony default export */ const mixin_notifier = (notifier);
;// CONCATENATED MODULE: ./node_modules/claygl/src/core/util.js
var guid = 0;

var ArrayProto = Array.prototype;
var nativeForEach = ArrayProto.forEach;

/**
 * Util functions
 * @namespace clay.core.util
 */
var util = {

    /**
     * Generate GUID
     * @return {number}
     * @memberOf clay.core.util
     */
    genGUID: function () {
        return ++guid;
    },
    /**
     * Relative path to absolute path
     * @param  {string} path
     * @param  {string} basePath
     * @return {string}
     * @memberOf clay.core.util
     */
    relative2absolute: function (path, basePath) {
        if (!basePath || path.match(/^\//)) {
            return path;
        }
        var pathParts = path.split('/');
        var basePathParts = basePath.split('/');

        var item = pathParts[0];
        while(item === '.' || item === '..') {
            if (item === '..') {
                basePathParts.pop();
            }
            pathParts.shift();
            item = pathParts[0];
        }
        return basePathParts.join('/') + '/' + pathParts.join('/');
    },

    /**
     * Extend target with source
     * @param  {Object} target
     * @param  {Object} source
     * @return {Object}
     * @memberOf clay.core.util
     */
    extend: function (target, source) {
        if (source) {
            for (var name in source) {
                if (source.hasOwnProperty(name)) {
                    target[name] = source[name];
                }
            }
        }
        return target;
    },

    /**
     * Extend properties to target if not exist.
     * @param  {Object} target
     * @param  {Object} source
     * @return {Object}
     * @memberOf clay.core.util
     */
    defaults: function (target, source) {
        if (source) {
            for (var propName in source) {
                if (target[propName] === undefined) {
                    target[propName] = source[propName];
                }
            }
        }
        return target;
    },
    /**
     * Extend properties with a given property list to avoid for..in.. iteration.
     * @param  {Object} target
     * @param  {Object} source
     * @param  {Array.<string>} propList
     * @return {Object}
     * @memberOf clay.core.util
     */
    extendWithPropList: function (target, source, propList) {
        if (source) {
            for (var i = 0; i < propList.length; i++) {
                var propName = propList[i];
                target[propName] = source[propName];
            }
        }
        return target;
    },
    /**
     * Extend properties to target if not exist. With a given property list avoid for..in.. iteration.
     * @param  {Object} target
     * @param  {Object} source
     * @param  {Array.<string>} propList
     * @return {Object}
     * @memberOf clay.core.util
     */
    defaultsWithPropList: function (target, source, propList) {
        if (source) {
            for (var i = 0; i < propList.length; i++) {
                var propName = propList[i];
                if (target[propName] == null) {
                    target[propName] = source[propName];
                }
            }
        }
        return target;
    },
    /**
     * @param  {Object|Array} obj
     * @param  {Function} iterator
     * @param  {Object} [context]
     * @memberOf clay.core.util
     */
    each: function (obj, iterator, context) {
        if (!(obj && iterator)) {
            return;
        }
        if (obj.forEach && obj.forEach === nativeForEach) {
            obj.forEach(iterator, context);
        }
        else if (obj.length === + obj.length) {
            for (var i = 0, len = obj.length; i < len; i++) {
                iterator.call(context, obj[i], i, obj);
            }
        }
        else {
            for (var key in obj) {
                if (obj.hasOwnProperty(key)) {
                    iterator.call(context, obj[key], key, obj);
                }
            }
        }
    },

    /**
     * Is object
     * @param  {}  obj
     * @return {boolean}
     * @memberOf clay.core.util
     */
    isObject: function (obj) {
        return obj === Object(obj);
    },

    /**
     * Is array ?
     * @param  {}  obj
     * @return {boolean}
     * @memberOf clay.core.util
     */
    isArray: function (obj) {
        return Array.isArray(obj);
    },

    /**
     * Is array like, which have a length property
     * @param  {}  obj
     * @return {boolean}
     * @memberOf clay.core.util
     */
    isArrayLike: function (obj) {
        if (!obj) {
            return false;
        }
        else {
            return obj.length === + obj.length;
        }
    },

    /**
     * @param  {} obj
     * @return {}
     * @memberOf clay.core.util
     */
    clone: function (obj) {
        if (!util.isObject(obj)) {
            return obj;
        }
        else if (util.isArray(obj)) {
            return obj.slice();
        }
        else if (util.isArrayLike(obj)) { // is typed array
            var ret = new obj.constructor(obj.length);
            for (var i = 0; i < obj.length; i++) {
                ret[i] = obj[i];
            }
            return ret;
        }
        else {
            return util.extend({}, obj);
        }
    }
};

/* harmony default export */ const core_util = (util);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/Base.js




/**
 * Base class of all objects
 * @constructor
 * @alias clay.core.Base
 * @mixes clay.core.mixin.notifier
 */
var Base = function () {
    /**
     * @type {number}
     */
    this.__uid__ = core_util.genGUID();
};

Base.__initializers__ = [
    function (opts) {
        core_util.extend(this, opts);
    }
];

core_util.extend(Base, mixin_extend);
core_util.extend(Base.prototype, mixin_notifier);

/* harmony default export */ const core_Base = (Base);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/GLInfo.js
var EXTENSION_LIST = [
    'OES_texture_float',
    'OES_texture_half_float',
    'OES_texture_float_linear',
    'OES_texture_half_float_linear',
    'OES_standard_derivatives',
    'OES_vertex_array_object',
    'OES_element_index_uint',
    'WEBGL_compressed_texture_s3tc',
    'WEBGL_depth_texture',
    'EXT_texture_filter_anisotropic',
    'EXT_shader_texture_lod',
    'WEBGL_draw_buffers',
    'EXT_frag_depth',
    'EXT_sRGB',
    'ANGLE_instanced_arrays'
];

var PARAMETER_NAMES = [
    'MAX_TEXTURE_SIZE',
    'MAX_CUBE_MAP_TEXTURE_SIZE'
];

function GLInfo(_gl) {
    var extensions = {};
    var parameters = {};

    // Get webgl extension
    for (var i = 0; i < EXTENSION_LIST.length; i++) {
        var extName = EXTENSION_LIST[i];
        createExtension(extName);
    }
    // Get parameters
    for (var i = 0; i < PARAMETER_NAMES.length; i++) {
        var name = PARAMETER_NAMES[i];
        parameters[name] = _gl.getParameter(_gl[name]);
    }

    this.getExtension = function (name) {
        if (!(name in extensions)) {
            createExtension(name);
        }
        return extensions[name];
    };

    this.getParameter = function (name) {
        return parameters[name];
    };

    function createExtension(name) {
        if (_gl.getExtension) {
            var ext = _gl.getExtension(name);
            if (!ext) {
                ext = _gl.getExtension('MOZ_' + name);
            }
            if (!ext) {
                ext = _gl.getExtension('WEBKIT_' + name);
            }
            extensions[name] = ext;
        }
    }
}

/* harmony default export */ const core_GLInfo = (GLInfo);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/glenum.js
/**
 * @namespace clay.core.glenum
 * @see http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
 */
/* harmony default export */ const glenum = ({
    /* ClearBufferMask */
    DEPTH_BUFFER_BIT               : 0x00000100,
    STENCIL_BUFFER_BIT             : 0x00000400,
    COLOR_BUFFER_BIT               : 0x00004000,

    /* BeginMode */
    POINTS                         : 0x0000,
    LINES                          : 0x0001,
    LINE_LOOP                      : 0x0002,
    LINE_STRIP                     : 0x0003,
    TRIANGLES                      : 0x0004,
    TRIANGLE_STRIP                 : 0x0005,
    TRIANGLE_FAN                   : 0x0006,

    /* AlphaFunction (not supported in ES20) */
    /*      NEVER */
    /*      LESS */
    /*      EQUAL */
    /*      LEQUAL */
    /*      GREATER */
    /*      NOTEQUAL */
    /*      GEQUAL */
    /*      ALWAYS */

    /* BlendingFactorDest */
    ZERO                           : 0,
    ONE                            : 1,
    SRC_COLOR                      : 0x0300,
    ONE_MINUS_SRC_COLOR            : 0x0301,
    SRC_ALPHA                      : 0x0302,
    ONE_MINUS_SRC_ALPHA            : 0x0303,
    DST_ALPHA                      : 0x0304,
    ONE_MINUS_DST_ALPHA            : 0x0305,

    /* BlendingFactorSrc */
    /*      ZERO */
    /*      ONE */
    DST_COLOR                      : 0x0306,
    ONE_MINUS_DST_COLOR            : 0x0307,
    SRC_ALPHA_SATURATE             : 0x0308,
    /*      SRC_ALPHA */
    /*      ONE_MINUS_SRC_ALPHA */
    /*      DST_ALPHA */
    /*      ONE_MINUS_DST_ALPHA */

    /* BlendEquationSeparate */
    FUNC_ADD                       : 0x8006,
    BLEND_EQUATION                 : 0x8009,
    BLEND_EQUATION_RGB             : 0x8009, /* same as BLEND_EQUATION */
    BLEND_EQUATION_ALPHA           : 0x883D,

    /* BlendSubtract */
    FUNC_SUBTRACT                  : 0x800A,
    FUNC_REVERSE_SUBTRACT          : 0x800B,

    /* Separate Blend Functions */
    BLEND_DST_RGB                  : 0x80C8,
    BLEND_SRC_RGB                  : 0x80C9,
    BLEND_DST_ALPHA                : 0x80CA,
    BLEND_SRC_ALPHA                : 0x80CB,
    CONSTANT_COLOR                 : 0x8001,
    ONE_MINUS_CONSTANT_COLOR       : 0x8002,
    CONSTANT_ALPHA                 : 0x8003,
    ONE_MINUS_CONSTANT_ALPHA       : 0x8004,
    BLEND_COLOR                    : 0x8005,

    /* Buffer Objects */
    ARRAY_BUFFER                   : 0x8892,
    ELEMENT_ARRAY_BUFFER           : 0x8893,
    ARRAY_BUFFER_BINDING           : 0x8894,
    ELEMENT_ARRAY_BUFFER_BINDING   : 0x8895,

    STREAM_DRAW                    : 0x88E0,
    STATIC_DRAW                    : 0x88E4,
    DYNAMIC_DRAW                   : 0x88E8,

    BUFFER_SIZE                    : 0x8764,
    BUFFER_USAGE                   : 0x8765,

    CURRENT_VERTEX_ATTRIB          : 0x8626,

    /* CullFaceMode */
    FRONT                          : 0x0404,
    BACK                           : 0x0405,
    FRONT_AND_BACK                 : 0x0408,

    /* DepthFunction */
    /*      NEVER */
    /*      LESS */
    /*      EQUAL */
    /*      LEQUAL */
    /*      GREATER */
    /*      NOTEQUAL */
    /*      GEQUAL */
    /*      ALWAYS */

    /* EnableCap */
    /* TEXTURE_2D */
    CULL_FACE                      : 0x0B44,
    BLEND                          : 0x0BE2,
    DITHER                         : 0x0BD0,
    STENCIL_TEST                   : 0x0B90,
    DEPTH_TEST                     : 0x0B71,
    SCISSOR_TEST                   : 0x0C11,
    POLYGON_OFFSET_FILL            : 0x8037,
    SAMPLE_ALPHA_TO_COVERAGE       : 0x809E,
    SAMPLE_COVERAGE                : 0x80A0,

    /* ErrorCode */
    NO_ERROR                       : 0,
    INVALID_ENUM                   : 0x0500,
    INVALID_VALUE                  : 0x0501,
    INVALID_OPERATION              : 0x0502,
    OUT_OF_MEMORY                  : 0x0505,

    /* FrontFaceDirection */
    CW                             : 0x0900,
    CCW                            : 0x0901,

    /* GetPName */
    LINE_WIDTH                     : 0x0B21,
    ALIASED_POINT_SIZE_RANGE       : 0x846D,
    ALIASED_LINE_WIDTH_RANGE       : 0x846E,
    CULL_FACE_MODE                 : 0x0B45,
    FRONT_FACE                     : 0x0B46,
    DEPTH_RANGE                    : 0x0B70,
    DEPTH_WRITEMASK                : 0x0B72,
    DEPTH_CLEAR_VALUE              : 0x0B73,
    DEPTH_FUNC                     : 0x0B74,
    STENCIL_CLEAR_VALUE            : 0x0B91,
    STENCIL_FUNC                   : 0x0B92,
    STENCIL_FAIL                   : 0x0B94,
    STENCIL_PASS_DEPTH_FAIL        : 0x0B95,
    STENCIL_PASS_DEPTH_PASS        : 0x0B96,
    STENCIL_REF                    : 0x0B97,
    STENCIL_VALUE_MASK             : 0x0B93,
    STENCIL_WRITEMASK              : 0x0B98,
    STENCIL_BACK_FUNC              : 0x8800,
    STENCIL_BACK_FAIL              : 0x8801,
    STENCIL_BACK_PASS_DEPTH_FAIL   : 0x8802,
    STENCIL_BACK_PASS_DEPTH_PASS   : 0x8803,
    STENCIL_BACK_REF               : 0x8CA3,
    STENCIL_BACK_VALUE_MASK        : 0x8CA4,
    STENCIL_BACK_WRITEMASK         : 0x8CA5,
    VIEWPORT                       : 0x0BA2,
    SCISSOR_BOX                    : 0x0C10,
    /*      SCISSOR_TEST */
    COLOR_CLEAR_VALUE              : 0x0C22,
    COLOR_WRITEMASK                : 0x0C23,
    UNPACK_ALIGNMENT               : 0x0CF5,
    PACK_ALIGNMENT                 : 0x0D05,
    MAX_TEXTURE_SIZE               : 0x0D33,
    MAX_VIEWPORT_DIMS              : 0x0D3A,
    SUBPIXEL_BITS                  : 0x0D50,
    RED_BITS                       : 0x0D52,
    GREEN_BITS                     : 0x0D53,
    BLUE_BITS                      : 0x0D54,
    ALPHA_BITS                     : 0x0D55,
    DEPTH_BITS                     : 0x0D56,
    STENCIL_BITS                   : 0x0D57,
    POLYGON_OFFSET_UNITS           : 0x2A00,
    /*      POLYGON_OFFSET_FILL */
    POLYGON_OFFSET_FACTOR          : 0x8038,
    TEXTURE_BINDING_2D             : 0x8069,
    SAMPLE_BUFFERS                 : 0x80A8,
    SAMPLES                        : 0x80A9,
    SAMPLE_COVERAGE_VALUE          : 0x80AA,
    SAMPLE_COVERAGE_INVERT         : 0x80AB,

    /* GetTextureParameter */
    /*      TEXTURE_MAG_FILTER */
    /*      TEXTURE_MIN_FILTER */
    /*      TEXTURE_WRAP_S */
    /*      TEXTURE_WRAP_T */

    COMPRESSED_TEXTURE_FORMATS     : 0x86A3,

    /* HintMode */
    DONT_CARE                      : 0x1100,
    FASTEST                        : 0x1101,
    NICEST                         : 0x1102,

    /* HintTarget */
    GENERATE_MIPMAP_HINT            : 0x8192,

    /* DataType */
    BYTE                           : 0x1400,
    UNSIGNED_BYTE                  : 0x1401,
    SHORT                          : 0x1402,
    UNSIGNED_SHORT                 : 0x1403,
    INT                            : 0x1404,
    UNSIGNED_INT                   : 0x1405,
    FLOAT                          : 0x1406,

    /* PixelFormat */
    DEPTH_COMPONENT                : 0x1902,
    ALPHA                          : 0x1906,
    RGB                            : 0x1907,
    RGBA                           : 0x1908,
    LUMINANCE                      : 0x1909,
    LUMINANCE_ALPHA                : 0x190A,

    /* PixelType */
    /*      UNSIGNED_BYTE */
    UNSIGNED_SHORT_4_4_4_4         : 0x8033,
    UNSIGNED_SHORT_5_5_5_1         : 0x8034,
    UNSIGNED_SHORT_5_6_5           : 0x8363,

    /* Shaders */
    FRAGMENT_SHADER                  : 0x8B30,
    VERTEX_SHADER                    : 0x8B31,
    MAX_VERTEX_ATTRIBS               : 0x8869,
    MAX_VERTEX_UNIFORM_VECTORS       : 0x8DFB,
    MAX_VARYING_VECTORS              : 0x8DFC,
    MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D,
    MAX_VERTEX_TEXTURE_IMAGE_UNITS   : 0x8B4C,
    MAX_TEXTURE_IMAGE_UNITS          : 0x8872,
    MAX_FRAGMENT_UNIFORM_VECTORS     : 0x8DFD,
    SHADER_TYPE                      : 0x8B4F,
    DELETE_STATUS                    : 0x8B80,
    LINK_STATUS                      : 0x8B82,
    VALIDATE_STATUS                  : 0x8B83,
    ATTACHED_SHADERS                 : 0x8B85,
    ACTIVE_UNIFORMS                  : 0x8B86,
    ACTIVE_ATTRIBUTES                : 0x8B89,
    SHADING_LANGUAGE_VERSION         : 0x8B8C,
    CURRENT_PROGRAM                  : 0x8B8D,

    /* StencilFunction */
    NEVER                          : 0x0200,
    LESS                           : 0x0201,
    EQUAL                          : 0x0202,
    LEQUAL                         : 0x0203,
    GREATER                        : 0x0204,
    NOTEQUAL                       : 0x0205,
    GEQUAL                         : 0x0206,
    ALWAYS                         : 0x0207,

    /* StencilOp */
    /*      ZERO */
    KEEP                           : 0x1E00,
    REPLACE                        : 0x1E01,
    INCR                           : 0x1E02,
    DECR                           : 0x1E03,
    INVERT                         : 0x150A,
    INCR_WRAP                      : 0x8507,
    DECR_WRAP                      : 0x8508,

    /* StringName */
    VENDOR                         : 0x1F00,
    RENDERER                       : 0x1F01,
    VERSION                        : 0x1F02,

    /* TextureMagFilter */
    NEAREST                        : 0x2600,
    LINEAR                         : 0x2601,

    /* TextureMinFilter */
    /*      NEAREST */
    /*      LINEAR */
    NEAREST_MIPMAP_NEAREST         : 0x2700,
    LINEAR_MIPMAP_NEAREST          : 0x2701,
    NEAREST_MIPMAP_LINEAR          : 0x2702,
    LINEAR_MIPMAP_LINEAR           : 0x2703,

    /* TextureParameterName */
    TEXTURE_MAG_FILTER             : 0x2800,
    TEXTURE_MIN_FILTER             : 0x2801,
    TEXTURE_WRAP_S                 : 0x2802,
    TEXTURE_WRAP_T                 : 0x2803,

    /* TextureTarget */
    TEXTURE_2D                     : 0x0DE1,
    TEXTURE                        : 0x1702,

    TEXTURE_CUBE_MAP               : 0x8513,
    TEXTURE_BINDING_CUBE_MAP       : 0x8514,
    TEXTURE_CUBE_MAP_POSITIVE_X    : 0x8515,
    TEXTURE_CUBE_MAP_NEGATIVE_X    : 0x8516,
    TEXTURE_CUBE_MAP_POSITIVE_Y    : 0x8517,
    TEXTURE_CUBE_MAP_NEGATIVE_Y    : 0x8518,
    TEXTURE_CUBE_MAP_POSITIVE_Z    : 0x8519,
    TEXTURE_CUBE_MAP_NEGATIVE_Z    : 0x851A,
    MAX_CUBE_MAP_TEXTURE_SIZE      : 0x851C,

    /* TextureUnit */
    TEXTURE0                       : 0x84C0,
    TEXTURE1                       : 0x84C1,
    TEXTURE2                       : 0x84C2,
    TEXTURE3                       : 0x84C3,
    TEXTURE4                       : 0x84C4,
    TEXTURE5                       : 0x84C5,
    TEXTURE6                       : 0x84C6,
    TEXTURE7                       : 0x84C7,
    TEXTURE8                       : 0x84C8,
    TEXTURE9                       : 0x84C9,
    TEXTURE10                      : 0x84CA,
    TEXTURE11                      : 0x84CB,
    TEXTURE12                      : 0x84CC,
    TEXTURE13                      : 0x84CD,
    TEXTURE14                      : 0x84CE,
    TEXTURE15                      : 0x84CF,
    TEXTURE16                      : 0x84D0,
    TEXTURE17                      : 0x84D1,
    TEXTURE18                      : 0x84D2,
    TEXTURE19                      : 0x84D3,
    TEXTURE20                      : 0x84D4,
    TEXTURE21                      : 0x84D5,
    TEXTURE22                      : 0x84D6,
    TEXTURE23                      : 0x84D7,
    TEXTURE24                      : 0x84D8,
    TEXTURE25                      : 0x84D9,
    TEXTURE26                      : 0x84DA,
    TEXTURE27                      : 0x84DB,
    TEXTURE28                      : 0x84DC,
    TEXTURE29                      : 0x84DD,
    TEXTURE30                      : 0x84DE,
    TEXTURE31                      : 0x84DF,
    ACTIVE_TEXTURE                 : 0x84E0,

    /* TextureWrapMode */
    REPEAT                         : 0x2901,
    CLAMP_TO_EDGE                  : 0x812F,
    MIRRORED_REPEAT                : 0x8370,

    /* Uniform Types */
    FLOAT_VEC2                     : 0x8B50,
    FLOAT_VEC3                     : 0x8B51,
    FLOAT_VEC4                     : 0x8B52,
    INT_VEC2                       : 0x8B53,
    INT_VEC3                       : 0x8B54,
    INT_VEC4                       : 0x8B55,
    BOOL                           : 0x8B56,
    BOOL_VEC2                      : 0x8B57,
    BOOL_VEC3                      : 0x8B58,
    BOOL_VEC4                      : 0x8B59,
    FLOAT_MAT2                     : 0x8B5A,
    FLOAT_MAT3                     : 0x8B5B,
    FLOAT_MAT4                     : 0x8B5C,
    SAMPLER_2D                     : 0x8B5E,
    SAMPLER_CUBE                   : 0x8B60,

    /* Vertex Arrays */
    VERTEX_ATTRIB_ARRAY_ENABLED        : 0x8622,
    VERTEX_ATTRIB_ARRAY_SIZE           : 0x8623,
    VERTEX_ATTRIB_ARRAY_STRIDE         : 0x8624,
    VERTEX_ATTRIB_ARRAY_TYPE           : 0x8625,
    VERTEX_ATTRIB_ARRAY_NORMALIZED     : 0x886A,
    VERTEX_ATTRIB_ARRAY_POINTER        : 0x8645,
    VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F,

    /* Shader Source */
    COMPILE_STATUS                 : 0x8B81,

    /* Shader Precision-Specified Types */
    LOW_FLOAT                      : 0x8DF0,
    MEDIUM_FLOAT                   : 0x8DF1,
    HIGH_FLOAT                     : 0x8DF2,
    LOW_INT                        : 0x8DF3,
    MEDIUM_INT                     : 0x8DF4,
    HIGH_INT                       : 0x8DF5,

    /* Framebuffer Object. */
    FRAMEBUFFER                    : 0x8D40,
    RENDERBUFFER                   : 0x8D41,

    RGBA4                          : 0x8056,
    RGB5_A1                        : 0x8057,
    RGB565                         : 0x8D62,
    DEPTH_COMPONENT16              : 0x81A5,
    STENCIL_INDEX                  : 0x1901,
    STENCIL_INDEX8                 : 0x8D48,
    DEPTH_STENCIL                  : 0x84F9,

    RENDERBUFFER_WIDTH             : 0x8D42,
    RENDERBUFFER_HEIGHT            : 0x8D43,
    RENDERBUFFER_INTERNAL_FORMAT   : 0x8D44,
    RENDERBUFFER_RED_SIZE          : 0x8D50,
    RENDERBUFFER_GREEN_SIZE        : 0x8D51,
    RENDERBUFFER_BLUE_SIZE         : 0x8D52,
    RENDERBUFFER_ALPHA_SIZE        : 0x8D53,
    RENDERBUFFER_DEPTH_SIZE        : 0x8D54,
    RENDERBUFFER_STENCIL_SIZE      : 0x8D55,

    FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           : 0x8CD0,
    FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           : 0x8CD1,
    FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         : 0x8CD2,
    FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3,

    COLOR_ATTACHMENT0              : 0x8CE0,
    DEPTH_ATTACHMENT               : 0x8D00,
    STENCIL_ATTACHMENT             : 0x8D20,
    DEPTH_STENCIL_ATTACHMENT       : 0x821A,

    NONE                           : 0,

    FRAMEBUFFER_COMPLETE                      : 0x8CD5,
    FRAMEBUFFER_INCOMPLETE_ATTACHMENT         : 0x8CD6,
    FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7,
    FRAMEBUFFER_INCOMPLETE_DIMENSIONS         : 0x8CD9,
    FRAMEBUFFER_UNSUPPORTED                   : 0x8CDD,

    FRAMEBUFFER_BINDING            : 0x8CA6,
    RENDERBUFFER_BINDING           : 0x8CA7,
    MAX_RENDERBUFFER_SIZE          : 0x84E8,

    INVALID_FRAMEBUFFER_OPERATION  : 0x0506,

    /* WebGL-specific enums */
    UNPACK_FLIP_Y_WEBGL            : 0x9240,
    UNPACK_PREMULTIPLY_ALPHA_WEBGL : 0x9241,
    CONTEXT_LOST_WEBGL             : 0x9242,
    UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243,
    BROWSER_DEFAULT_WEBGL          : 0x9244,
});

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/request.js
function get(options) {

    var xhr = new XMLHttpRequest();

    xhr.open('get', options.url);
    // With response type set browser can get and put binary data
    // https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data
    // Default is text, and it can be set
    // arraybuffer, blob, document, json, text
    xhr.responseType = options.responseType || 'text';

    if (options.onprogress) {
        //https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest
        xhr.onprogress = function(e) {
            if (e.lengthComputable) {
                var percent = e.loaded / e.total;
                options.onprogress(percent, e.loaded, e.total);
            }
            else {
                options.onprogress(null);
            }
        };
    }
    xhr.onload = function(e) {
        if (xhr.status >= 400) {
            options.onerror && options.onerror();
        }
        else {
            options.onload && options.onload(xhr.response);
        }
    };
    if (options.onerror) {
        xhr.onerror = options.onerror;
    }
    xhr.send(null);
}

/* harmony default export */ const request = ({
    get: get
});

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/vendor.js


var supportWebGL;

var vendor = {};

/**
 * If support WebGL
 * @return {boolean}
 */
vendor.supportWebGL = function () {
    if (supportWebGL == null) {
        try {
            var canvas = document.createElement('canvas');
            var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
            if (!gl) {
                throw new Error();
            }
        }
        catch (e) {
            supportWebGL = false;
        }

    }
    return supportWebGL;
};

vendor.Int8Array = typeof Int8Array === 'undefined' ? Array : Int8Array;

vendor.Uint8Array = typeof Uint8Array === 'undefined' ? Array : Uint8Array;

vendor.Uint16Array = typeof Uint16Array === 'undefined' ? Array : Uint16Array;

vendor.Uint32Array = typeof Uint32Array === 'undefined' ? Array : Uint32Array;

vendor.Int16Array = typeof Int16Array === 'undefined' ? Array : Int16Array;

vendor.Float32Array = typeof Float32Array === 'undefined' ? Array : Float32Array;

vendor.Float64Array = typeof Float64Array === 'undefined' ? Array : Float64Array;

var g = {};
if (typeof window !== 'undefined') {
    g = window;
}
else if (typeof __webpack_require__.g !== 'undefined') {
    g = __webpack_require__.g;
}


vendor.requestAnimationFrame = g.requestAnimationFrame
    || g.msRequestAnimationFrame
    || g.mozRequestAnimationFrame
    || g.webkitRequestAnimationFrame
    || function (func){ setTimeout(func, 16); };

vendor.createCanvas = function () {
    return document.createElement('canvas');
};

vendor.createImage = function () {
    return new g.Image();
};

vendor.request = {
    get: request.get
};

vendor.addEventListener = function (dom, type, func, useCapture) {
    dom.addEventListener(type, func, useCapture);
};

vendor.removeEventListener = function (dom, type, func) {
    dom.removeEventListener(type, func);
};

/* harmony default export */ const core_vendor = (vendor);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/LinkedList.js
/**
 * Simple double linked list. Compared with array, it has O(1) remove operation.
 * @constructor
 * @alias clay.core.LinkedList
 */
var LinkedList = function () {

    /**
     * @type {clay.core.LinkedList.Entry}
     */
    this.head = null;

    /**
     * @type {clay.core.LinkedList.Entry}
     */
    this.tail = null;

    this._length = 0;
};

/**
 * Insert a new value at the tail
 * @param  {} val
 * @return {clay.core.LinkedList.Entry}
 */
LinkedList.prototype.insert = function (val) {
    var entry = new LinkedList.Entry(val);
    this.insertEntry(entry);
    return entry;
};

/**
 * Insert a new value at idx
 * @param {number} idx
 * @param  {} val
 * @return {clay.core.LinkedList.Entry}
 */
LinkedList.prototype.insertAt = function (idx, val) {
    if (idx < 0) {
        return;
    }
    var next = this.head;
    var cursor = 0;
    while (next && cursor != idx) {
        next = next.next;
        cursor++;
    }
    if (next) {
        var entry = new LinkedList.Entry(val);
        var prev = next.prev;
        if (!prev) { //next is head
            this.head = entry;
        }
        else {
            prev.next = entry;
            entry.prev = prev;
        }
        entry.next = next;
        next.prev = entry;
    }
    else {
        this.insert(val);
    }
};

LinkedList.prototype.insertBeforeEntry = function (val, next) {
    var entry = new LinkedList.Entry(val);
    var prev = next.prev;
    if (!prev) { //next is head
        this.head = entry;
    }
    else {
        prev.next = entry;
        entry.prev = prev;
    }
    entry.next = next;
    next.prev = entry;

    this._length++;
};

/**
 * Insert an entry at the tail
 * @param  {clay.core.LinkedList.Entry} entry
 */
LinkedList.prototype.insertEntry = function (entry) {
    if (!this.head) {
        this.head = this.tail = entry;
    }
    else {
        this.tail.next = entry;
        entry.prev = this.tail;
        this.tail = entry;
    }
    this._length++;
};

/**
 * Remove entry.
 * @param  {clay.core.LinkedList.Entry} entry
 */
LinkedList.prototype.remove = function (entry) {
    var prev = entry.prev;
    var next = entry.next;
    if (prev) {
        prev.next = next;
    }
    else {
        // Is head
        this.head = next;
    }
    if (next) {
        next.prev = prev;
    }
    else {
        // Is tail
        this.tail = prev;
    }
    entry.next = entry.prev = null;
    this._length--;
};

/**
 * Remove entry at index.
 * @param  {number} idx
 * @return {}
 */
LinkedList.prototype.removeAt = function (idx) {
    if (idx < 0) {
        return;
    }
    var curr = this.head;
    var cursor = 0;
    while (curr && cursor != idx) {
        curr = curr.next;
        cursor++;
    }
    if (curr) {
        this.remove(curr);
        return curr.value;
    }
};
/**
 * Get head value
 * @return {}
 */
LinkedList.prototype.getHead = function () {
    if (this.head) {
        return this.head.value;
    }
};
/**
 * Get tail value
 * @return {}
 */
LinkedList.prototype.getTail = function () {
    if (this.tail) {
        return this.tail.value;
    }
};
/**
 * Get value at idx
 * @param {number} idx
 * @return {}
 */
LinkedList.prototype.getAt = function (idx) {
    if (idx < 0) {
        return;
    }
    var curr = this.head;
    var cursor = 0;
    while (curr && cursor != idx) {
        curr = curr.next;
        cursor++;
    }
    return curr.value;
};

/**
 * @param  {} value
 * @return {number}
 */
LinkedList.prototype.indexOf = function (value) {
    var curr = this.head;
    var cursor = 0;
    while (curr) {
        if (curr.value === value) {
            return cursor;
        }
        curr = curr.next;
        cursor++;
    }
};

/**
 * @return {number}
 */
LinkedList.prototype.length = function () {
    return this._length;
};

/**
 * If list is empty
 */
LinkedList.prototype.isEmpty = function () {
    return this._length === 0;
};

/**
 * @param  {Function} cb
 * @param  {} context
 */
LinkedList.prototype.forEach = function (cb, context) {
    var curr = this.head;
    var idx = 0;
    var haveContext = typeof(context) != 'undefined';
    while (curr) {
        if (haveContext) {
            cb.call(context, curr.value, idx);
        }
        else {
            cb(curr.value, idx);
        }
        curr = curr.next;
        idx++;
    }
};

/**
 * Clear the list
 */
LinkedList.prototype.clear = function () {
    this.tail = this.head = null;
    this._length = 0;
};

/**
 * @constructor
 * @param {} val
 */
LinkedList.Entry = function (val) {
    /**
     * @type {}
     */
    this.value = val;

    /**
     * @type {clay.core.LinkedList.Entry}
     */
    this.next = null;

    /**
     * @type {clay.core.LinkedList.Entry}
     */
    this.prev = null;
};

/* harmony default export */ const core_LinkedList = (LinkedList);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/LRU.js


/**
 * LRU Cache
 * @constructor
 * @alias clay.core.LRU
 */
var LRU = function (maxSize) {

    this._list = new core_LinkedList();

    this._map = {};

    this._maxSize = maxSize || 10;
};

/**
 * Set cache max size
 * @param {number} size
 */
LRU.prototype.setMaxSize = function (size) {
    this._maxSize = size;
};

/**
 * @param  {string} key
 * @param  {} value
 */
LRU.prototype.put = function (key, value) {
    if (!this._map.hasOwnProperty(key)) {
        var len = this._list.length();
        if (len >= this._maxSize && len > 0) {
            // Remove the least recently used
            var leastUsedEntry = this._list.head;
            this._list.remove(leastUsedEntry);
            delete this._map[leastUsedEntry.key];
        }

        var entry = this._list.insert(value);
        entry.key = key;
        this._map[key] = entry;
    }
};

/**
 * @param  {string} key
 * @return {}
 */
LRU.prototype.get = function (key) {
    var entry = this._map[key];
    if (this._map.hasOwnProperty(key)) {
        // Put the latest used entry in the tail
        if (entry !== this._list.tail) {
            this._list.remove(entry);
            this._list.insertEntry(entry);
        }

        return entry.value;
    }
};

/**
 * @param {string} key
 */
LRU.prototype.remove = function (key) {
    var entry = this._map[key];
    if (typeof(entry) !== 'undefined') {
        delete this._map[key];
        this._list.remove(entry);
    }
};

/**
 * Clear the cache
 */
LRU.prototype.clear = function () {
    this._list.clear();
    this._map = {};
};

/* harmony default export */ const core_LRU = (LRU);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/color.js
/**
 * @namespace clay.core.color
 */


var colorUtil = {};

var kCSSColorTable = {
    'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1],
    'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1],
    'aquamarine': [127,255,212,1], 'azure': [240,255,255,1],
    'beige': [245,245,220,1], 'bisque': [255,228,196,1],
    'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1],
    'blue': [0,0,255,1], 'blueviolet': [138,43,226,1],
    'brown': [165,42,42,1], 'burlywood': [222,184,135,1],
    'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1],
    'chocolate': [210,105,30,1], 'coral': [255,127,80,1],
    'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1],
    'crimson': [220,20,60,1], 'cyan': [0,255,255,1],
    'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1],
    'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1],
    'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1],
    'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1],
    'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1],
    'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1],
    'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1],
    'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1],
    'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1],
    'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1],
    'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1],
    'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1],
    'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1],
    'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1],
    'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1],
    'gold': [255,215,0,1], 'goldenrod': [218,165,32,1],
    'gray': [128,128,128,1], 'green': [0,128,0,1],
    'greenyellow': [173,255,47,1], 'grey': [128,128,128,1],
    'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1],
    'indianred': [205,92,92,1], 'indigo': [75,0,130,1],
    'ivory': [255,255,240,1], 'khaki': [240,230,140,1],
    'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1],
    'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1],
    'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1],
    'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1],
    'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1],
    'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1],
    'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1],
    'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1],
    'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1],
    'lightyellow': [255,255,224,1], 'lime': [0,255,0,1],
    'limegreen': [50,205,50,1], 'linen': [250,240,230,1],
    'magenta': [255,0,255,1], 'maroon': [128,0,0,1],
    'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1],
    'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1],
    'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1],
    'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1],
    'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1],
    'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1],
    'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1],
    'navy': [0,0,128,1], 'oldlace': [253,245,230,1],
    'olive': [128,128,0,1], 'olivedrab': [107,142,35,1],
    'orange': [255,165,0,1], 'orangered': [255,69,0,1],
    'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1],
    'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1],
    'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1],
    'peachpuff': [255,218,185,1], 'peru': [205,133,63,1],
    'pink': [255,192,203,1], 'plum': [221,160,221,1],
    'powderblue': [176,224,230,1], 'purple': [128,0,128,1],
    'red': [255,0,0,1], 'rosybrown': [188,143,143,1],
    'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1],
    'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1],
    'seagreen': [46,139,87,1], 'seashell': [255,245,238,1],
    'sienna': [160,82,45,1], 'silver': [192,192,192,1],
    'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1],
    'slategray': [112,128,144,1], 'slategrey': [112,128,144,1],
    'snow': [255,250,250,1], 'springgreen': [0,255,127,1],
    'steelblue': [70,130,180,1], 'tan': [210,180,140,1],
    'teal': [0,128,128,1], 'thistle': [216,191,216,1],
    'tomato': [255,99,71,1], 'turquoise': [64,224,208,1],
    'violet': [238,130,238,1], 'wheat': [245,222,179,1],
    'white': [255,255,255,1], 'whitesmoke': [245,245,245,1],
    'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1]
};

function clampCssByte(i) {  // Clamp to integer 0 .. 255.
    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).
    return i < 0 ? 0 : i > 255 ? 255 : i;
}

function clampCssAngle(i) {  // Clamp to integer 0 .. 360.
    i = Math.round(i);  // Seems to be what Chrome does (vs truncation).
    return i < 0 ? 0 : i > 360 ? 360 : i;
}

function clampCssFloat(f) {  // Clamp to float 0.0 .. 1.0.
    return f < 0 ? 0 : f > 1 ? 1 : f;
}

function parseCssInt(str) {  // int or percentage.
    if (str.length && str.charAt(str.length - 1) === '%') {
        return clampCssByte(parseFloat(str) / 100 * 255);
    }
    return clampCssByte(parseInt(str, 10));
}

function parseCssFloat(str) {  // float or percentage.
    if (str.length && str.charAt(str.length - 1) === '%') {
        return clampCssFloat(parseFloat(str) / 100);
    }
    return clampCssFloat(parseFloat(str));
}

function cssHueToRgb(m1, m2, h) {
    if (h < 0) {
        h += 1;
    }
    else if (h > 1) {
        h -= 1;
    }

    if (h * 6 < 1) {
        return m1 + (m2 - m1) * h * 6;
    }
    if (h * 2 < 1) {
        return m2;
    }
    if (h * 3 < 2) {
        return m1 + (m2 - m1) * (2/3 - h) * 6;
    }
    return m1;
}

function lerpNumber(a, b, p) {
    return a + (b - a) * p;
}

function setRgba(out, r, g, b, a) {
    out[0] = r; out[1] = g; out[2] = b; out[3] = a;
    return out;
}
function copyRgba(out, a) {
    out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3];
    return out;
}

var colorCache = new core_LRU(20);
var lastRemovedArr = null;

function putToCache(colorStr, rgbaArr) {
    // Reuse removed array
    if (lastRemovedArr) {
        copyRgba(lastRemovedArr, rgbaArr);
    }
    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice()));
}

/**
 * @name clay.core.color.parse
 * @param {string} colorStr
 * @param {Array.<number>} out
 * @return {Array.<number>}
 */
colorUtil.parse = function (colorStr, rgbaArr) {
    if (!colorStr) {
        return;
    }
    rgbaArr = rgbaArr || [];

    var cached = colorCache.get(colorStr);
    if (cached) {
        return copyRgba(rgbaArr, cached);
    }

    // colorStr may be not string
    colorStr = colorStr + '';
    // Remove all whitespace, not compliant, but should just be more accepting.
    var str = colorStr.replace(/ /g, '').toLowerCase();

    // Color keywords (and transparent) lookup.
    if (str in kCSSColorTable) {
        copyRgba(rgbaArr, kCSSColorTable[str]);
        putToCache(colorStr, rgbaArr);
        return rgbaArr;
    }

    // #abc and #abc123 syntax.
    if (str.charAt(0) === '#') {
        if (str.length === 4) {
            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.
            if (!(iv >= 0 && iv <= 0xfff)) {
                setRgba(rgbaArr, 0, 0, 0, 1);
                return;  // Covers NaN.
            }
            setRgba(rgbaArr,
                ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8),
                (iv & 0xf0) | ((iv & 0xf0) >> 4),
                (iv & 0xf) | ((iv & 0xf) << 4),
                1
            );
            putToCache(colorStr, rgbaArr);
            return rgbaArr;
        }
        else if (str.length === 7) {
            var iv = parseInt(str.substr(1), 16);  // TODO(deanm): Stricter parsing.
            if (!(iv >= 0 && iv <= 0xffffff)) {
                setRgba(rgbaArr, 0, 0, 0, 1);
                return;  // Covers NaN.
            }
            setRgba(rgbaArr,
                (iv & 0xff0000) >> 16,
                (iv & 0xff00) >> 8,
                iv & 0xff,
                1
            );
            putToCache(colorStr, rgbaArr);
            return rgbaArr;
        }

        return;
    }
    var op = str.indexOf('('), ep = str.indexOf(')');
    if (op !== -1 && ep + 1 === str.length) {
        var fname = str.substr(0, op);
        var params = str.substr(op + 1, ep - (op + 1)).split(',');
        var alpha = 1;  // To allow case fallthrough.
        switch (fname) {
            case 'rgba':
                if (params.length !== 4) {
                    setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                alpha = parseCssFloat(params.pop()); // jshint ignore:line
            // Fall through.
            case 'rgb':
                if (params.length !== 3) {
                    setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                setRgba(rgbaArr,
                    parseCssInt(params[0]),
                    parseCssInt(params[1]),
                    parseCssInt(params[2]),
                    alpha
                );
                putToCache(colorStr, rgbaArr);
                return rgbaArr;
            case 'hsla':
                if (params.length !== 4) {
                    setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                params[3] = parseCssFloat(params[3]);
                hsla2rgba(params, rgbaArr);
                putToCache(colorStr, rgbaArr);
                return rgbaArr;
            case 'hsl':
                if (params.length !== 3) {
                    setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                hsla2rgba(params, rgbaArr);
                putToCache(colorStr, rgbaArr);
                return rgbaArr;
            default:
                return;
        }
    }

    setRgba(rgbaArr, 0, 0, 0, 1);
    return;
};

colorUtil.parseToFloat = function (colorStr, rgbaArr) {
    rgbaArr = colorUtil.parse(colorStr, rgbaArr);
    if (!rgbaArr) {
        return;
    }
    rgbaArr[0] /= 255;
    rgbaArr[1] /= 255;
    rgbaArr[2] /= 255;
    return rgbaArr;
}

/**
 * @name clay.core.color.hsla2rgba
 * @param {Array.<number>} hsla
 * @param {Array.<number>} rgba
 * @return {Array.<number>} rgba
 */
function hsla2rgba(hsla, rgba) {
    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;  // 0 .. 1
    // NOTE(deanm): According to the CSS spec s/l should only be
    // percentages, but we don't bother and let float or percentage.
    var s = parseCssFloat(hsla[1]);
    var l = parseCssFloat(hsla[2]);
    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
    var m1 = l * 2 - m2;

    rgba = rgba || [];
    setRgba(rgba,
        clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255),
        clampCssByte(cssHueToRgb(m1, m2, h) * 255),
        clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255),
        1
    );

    if (hsla.length === 4) {
        rgba[3] = hsla[3];
    }

    return rgba;
}

/**
 * @name clay.core.color.rgba2hsla
 * @param {Array.<number>} rgba
 * @return {Array.<number>} hsla
 */
function rgba2hsla(rgba) {
    if (!rgba) {
        return;
    }

    // RGB from 0 to 255
    var R = rgba[0] / 255;
    var G = rgba[1] / 255;
    var B = rgba[2] / 255;

    var vMin = Math.min(R, G, B); // Min. value of RGB
    var vMax = Math.max(R, G, B); // Max. value of RGB
    var delta = vMax - vMin; // Delta RGB value

    var L = (vMax + vMin) / 2;
    var H;
    var S;
    // HSL results from 0 to 1
    if (delta === 0) {
        H = 0;
        S = 0;
    }
    else {
        if (L < 0.5) {
            S = delta / (vMax + vMin);
        }
        else {
            S = delta / (2 - vMax - vMin);
        }

        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;

        if (R === vMax) {
            H = deltaB - deltaG;
        }
        else if (G === vMax) {
            H = (1 / 3) + deltaR - deltaB;
        }
        else if (B === vMax) {
            H = (2 / 3) + deltaG - deltaR;
        }

        if (H < 0) {
            H += 1;
        }

        if (H > 1) {
            H -= 1;
        }
    }

    var hsla = [H * 360, S, L];

    if (rgba[3] != null) {
        hsla.push(rgba[3]);
    }

    return hsla;
}

/**
 * @name clay.core.color.lift
 * @param {string} color
 * @param {number} level
 * @return {string}
 */
colorUtil.lift = function (color, level) {
    var colorArr = colorUtil.parse(color);
    if (colorArr) {
        for (var i = 0; i < 3; i++) {
            if (level < 0) {
                colorArr[i] = colorArr[i] * (1 - level) | 0;
            }
            else {
                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
            }
        }
        return colorUtil.stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
    }
}

/**
 * @name clay.core.color.toHex
 * @param {string} color
 * @return {string}
 */
colorUtil.toHex = function (color) {
    var colorArr = colorUtil.parse(color);
    if (colorArr) {
        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
    }
};

/**
 * Map value to color. Faster than lerp methods because color is represented by rgba array.
 * @name clay.core.color
 * @param {number} normalizedValue A float between 0 and 1.
 * @param {Array.<Array.<number>>} colors List of rgba color array
 * @param {Array.<number>} [out] Mapped gba color array
 * @return {Array.<number>} will be null/undefined if input illegal.
 */
colorUtil.fastLerp = function (normalizedValue, colors, out) {
    if (!(colors && colors.length)
        || !(normalizedValue >= 0 && normalizedValue <= 1)
    ) {
        return;
    }

    out = out || [];

    var value = normalizedValue * (colors.length - 1);
    var leftIndex = Math.floor(value);
    var rightIndex = Math.ceil(value);
    var leftColor = colors[leftIndex];
    var rightColor = colors[rightIndex];
    var dv = value - leftIndex;
    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));
    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));
    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));
    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));

    return out;
}

colorUtil.fastMapToColor = colorUtil.fastLerp;

/**
 * @param {number} normalizedValue A float between 0 and 1.
 * @param {Array.<string>} colors Color list.
 * @param {boolean=} fullOutput Default false.
 * @return {(string|Object)} Result color. If fullOutput,
 *                           return {color: ..., leftIndex: ..., rightIndex: ..., value: ...},
 */
colorUtil.lerp = function (normalizedValue, colors, fullOutput) {
    if (!(colors && colors.length)
        || !(normalizedValue >= 0 && normalizedValue <= 1)
    ) {
        return;
    }

    var value = normalizedValue * (colors.length - 1);
    var leftIndex = Math.floor(value);
    var rightIndex = Math.ceil(value);
    var leftColor = colorUtil.parse(colors[leftIndex]);
    var rightColor = colorUtil.parse(colors[rightIndex]);
    var dv = value - leftIndex;

    var color = colorUtil.stringify(
        [
            clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)),
            clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)),
            clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)),
            clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))
        ],
        'rgba'
    );

    return fullOutput
        ? {
            color: color,
            leftIndex: leftIndex,
            rightIndex: rightIndex,
            value: value
        }
        : color;
}

/**
 * @deprecated
 */
colorUtil.mapToColor = colorUtil.lerp;

/**
 * @name clay.core.color
 * @param {string} color
 * @param {number=} h 0 ~ 360, ignore when null.
 * @param {number=} s 0 ~ 1, ignore when null.
 * @param {number=} l 0 ~ 1, ignore when null.
 * @return {string} Color string in rgba format.
 */
colorUtil.modifyHSL = function (color, h, s, l) {
    color = colorUtil.parse(color);

    if (color) {
        color = rgba2hsla(color);
        h != null && (color[0] = clampCssAngle(h));
        s != null && (color[1] = parseCssFloat(s));
        l != null && (color[2] = parseCssFloat(l));

        return colorUtil.stringify(hsla2rgba(color), 'rgba');
    }
}

/**
 * @param {string} color
 * @param {number=} alpha 0 ~ 1
 * @return {string} Color string in rgba format.
 */
colorUtil.modifyAlpha = function (color, alpha) {
    color = colorUtil.parse(color);

    if (color && alpha != null) {
        color[3] = clampCssFloat(alpha);
        return colorUtil.stringify(color, 'rgba');
    }
}

/**
 * @param {Array.<number>} arrColor like [12,33,44,0.4]
 * @param {string} type 'rgba', 'hsva', ...
 * @return {string} Result color. (If input illegal, return undefined).
 */
colorUtil.stringify = function (arrColor, type) {
    if (!arrColor || !arrColor.length) {
        return;
    }
    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
        colorStr += ',' + arrColor[3];
    }
    return type + '(' + colorStr + ')';
};



/* harmony default export */ const color = (colorUtil);
;// CONCATENATED MODULE: ./node_modules/claygl/src/Material.js



var parseColor = color.parseToFloat;

var programKeyCache = {};

function getDefineCode(defines) {
    var defineKeys = Object.keys(defines);
    defineKeys.sort();
    var defineStr = [];
    // Custom Defines
    for (var i = 0; i < defineKeys.length; i++) {
        var key = defineKeys[i];
        var value = defines[key];
        if (value === null) {
            defineStr.push(key);
        }
        else{
            defineStr.push(key + ' ' + value.toString());
        }
    }
    return defineStr.join('\n');
}

function getProgramKey(vertexDefines, fragmentDefines, enabledTextures) {
    enabledTextures.sort();
    var defineStr = [];
    for (var i = 0; i < enabledTextures.length; i++) {
        var symbol = enabledTextures[i];
        defineStr.push(symbol);
    }
    var key = getDefineCode(vertexDefines) + '\n'
        + getDefineCode(fragmentDefines) + '\n'
        + defineStr.join('\n');

    if (programKeyCache[key]) {
        return programKeyCache[key];
    }

    var id = core_util.genGUID();
    programKeyCache[key] = id;
    return id;
}

/**
 * Material defines the appearance of mesh surface, like `color`, `roughness`, `metalness`, etc.
 * It contains a {@link clay.Shader} and corresponding uniforms.
 *
 * Here is a basic example to create a standard material
```js
var material = new clay.Material({
    shader: new clay.Shader(
        clay.Shader.source('clay.vertex'),
        clay.Shader.source('clay.fragment')
    )
});
```
 * @constructor clay.Material
 * @extends clay.core.Base
 */
var Material = core_Base.extend(function () {
    return /** @lends clay.Material# */ {
        /**
         * @type {string}
         */
        name: '',

        /**
         * @type {Object}
         */
        // uniforms: null,

        /**
         * @type {clay.Shader}
         */
        // shader: null,

        /**
         * @type {boolean}
         */
        depthTest: true,

        /**
         * @type {boolean}
         */
        depthMask: true,

        /**
         * @type {boolean}
         */
        transparent: false,
        /**
         * Blend func is a callback function when the material
         * have custom blending
         * The gl context will be the only argument passed in tho the
         * blend function
         * Detail of blend function in WebGL:
         * http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf
         *
         * Example :
         * function(_gl) {
         *  _gl.blendEquation(_gl.FUNC_ADD);
         *  _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA);
         * }
         */
        blend: null,

        /**
         * If update texture status automatically.
         */
        autoUpdateTextureStatus: true,

        uniforms: {},
        vertexDefines: {},
        fragmentDefines: {},
        _textureStatus: {},

        // shadowTransparentMap : null

        // PENDING enable the uniform that only used in shader.
        _enabledUniforms: null,
    };
}, function () {
    if (!this.name) {
        this.name = 'MATERIAL_' + this.__uid__;
    }

    if (this.shader) {
        // Keep status, mainly preset uniforms, vertexDefines and fragmentDefines
        this.attachShader(this.shader, true);
    }
},
/** @lends clay.Material.prototype */
{
    precision: 'highp',

    /**
     * Set material uniform
     * @example
     *  mat.setUniform('color', [1, 1, 1, 1]);
     * @param {string} symbol
     * @param {number|array|clay.Texture|ArrayBufferView} value
     */
    setUniform: function (symbol, value) {
        if (value === undefined) {
            console.warn('Uniform value "' + symbol + '" is undefined');
        }
        var uniform = this.uniforms[symbol];
        if (uniform) {

            if (typeof value === 'string') {
                // Try to parse as a color. Invalid color string will return null.
                value = parseColor(value) || value;
            }

            uniform.value = value;

            if (this.autoUpdateTextureStatus && uniform.type === 't') {
                if (value) {
                    this.enableTexture(symbol);
                }
                else {
                    this.disableTexture(symbol);
                }
            }
        }
    },

    /**
     * @param {Object} obj
     */
    setUniforms: function(obj) {
        for (var key in obj) {
            var val = obj[key];
            this.setUniform(key, val);
        }
    },

    /**
     * @param  {string}  symbol
     * @return {boolean}
     */
    isUniformEnabled: function (symbol) {
        return this._enabledUniforms.indexOf(symbol) >= 0;
    },

    getEnabledUniforms: function () {
        return this._enabledUniforms;
    },
    getTextureUniforms: function () {
        return this._textureUniforms;
    },

    /**
     * Alias of setUniform and setUniforms
     * @param {object|string} symbol
     * @param {number|array|clay.Texture|ArrayBufferView} [value]
     */
    set: function (symbol, value) {
        if (typeof(symbol) === 'object') {
            for (var key in symbol) {
                var val = symbol[key];
                this.setUniform(key, val);
            }
        }
        else {
            this.setUniform(symbol, value);
        }
    },
    /**
     * Get uniform value
     * @param  {string} symbol
     * @return {number|array|clay.Texture|ArrayBufferView}
     */
    get: function (symbol) {
        var uniform = this.uniforms[symbol];
        if (uniform) {
            return uniform.value;
        }
    },
    /**
     * Attach a shader instance
     * @param  {clay.Shader} shader
     * @param  {boolean} keepStatus If try to keep uniform and texture
     */
    attachShader: function(shader, keepStatus) {
        var originalUniforms = this.uniforms;

        // Ignore if uniform can use in shader.
        this.uniforms = shader.createUniforms();
        this.shader = shader;

        var uniforms = this.uniforms;
        this._enabledUniforms = Object.keys(uniforms);
        // Make sure uniforms are set in same order to avoid texture slot wrong
        this._enabledUniforms.sort();
        this._textureUniforms = this._enabledUniforms.filter(function (uniformName) {
            var type = this.uniforms[uniformName].type;
            return type === 't' || type === 'tv';
        }, this);

        var originalVertexDefines = this.vertexDefines;
        var originalFragmentDefines = this.fragmentDefines;

        this.vertexDefines = core_util.clone(shader.vertexDefines);
        this.fragmentDefines = core_util.clone(shader.fragmentDefines);

        if (keepStatus) {
            for (var symbol in originalUniforms) {
                if (uniforms[symbol]) {
                    uniforms[symbol].value = originalUniforms[symbol].value;
                }
            }

            core_util.defaults(this.vertexDefines, originalVertexDefines);
            core_util.defaults(this.fragmentDefines, originalFragmentDefines);
        }

        var textureStatus = {};
        for (var key in shader.textures) {
            textureStatus[key] = {
                shaderType: shader.textures[key].shaderType,
                type: shader.textures[key].type,
                enabled: (keepStatus && this._textureStatus[key]) ? this._textureStatus[key].enabled : false
            };
        }

        this._textureStatus = textureStatus;

        this._programKey = '';
    },

    /**
     * Clone a new material and keep uniforms, shader will not be cloned
     * @return {clay.Material}
     */
    clone: function () {
        var material = new this.constructor({
            name: this.name,
            shader: this.shader
        });
        for (var symbol in this.uniforms) {
            material.uniforms[symbol].value = this.uniforms[symbol].value;
        }
        material.depthTest = this.depthTest;
        material.depthMask = this.depthMask;
        material.transparent = this.transparent;
        material.blend = this.blend;

        material.vertexDefines = core_util.clone(this.vertexDefines);
        material.fragmentDefines = core_util.clone(this.fragmentDefines);
        material.enableTexture(this.getEnabledTextures());
        material.precision = this.precision;

        return material;
    },

    /**
     * Add a #define macro in shader code
     * @param  {string} shaderType Can be vertex, fragment or both
     * @param  {string} symbol
     * @param  {number} [val]
     */
    define: function (shaderType, symbol, val) {
        var vertexDefines = this.vertexDefines;
        var fragmentDefines = this.fragmentDefines;
        if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both'
            && arguments.length < 3
        ) {
            // shaderType default to be 'both'
            val = symbol;
            symbol = shaderType;
            shaderType = 'both';
        }
        val = val != null ? val : null;
        if (shaderType === 'vertex' || shaderType === 'both') {
            if (vertexDefines[symbol] !== val) {
                vertexDefines[symbol] = val;
                // Mark as dirty
                this._programKey = '';
            }
        }
        if (shaderType === 'fragment' || shaderType === 'both') {
            if (fragmentDefines[symbol] !== val) {
                fragmentDefines[symbol] = val;
                if (shaderType !== 'both') {
                    this._programKey = '';
                }
            }
        }
    },

    /**
     * Remove a #define macro in shader code
     * @param  {string} shaderType Can be vertex, fragment or both
     * @param  {string} symbol
     */
    undefine: function (shaderType, symbol) {
        if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both'
            && arguments.length < 2
        ) {
            // shaderType default to be 'both'
            symbol = shaderType;
            shaderType = 'both';
        }
        if (shaderType === 'vertex' || shaderType === 'both') {
            if (this.isDefined('vertex', symbol)) {
                delete this.vertexDefines[symbol];
                // Mark as dirty
                this._programKey = '';
            }
        }
        if (shaderType === 'fragment' || shaderType === 'both') {
            if (this.isDefined('fragment', symbol)) {
                delete this.fragmentDefines[symbol];
                if (shaderType !== 'both') {
                    this._programKey = '';
                }
            }
        }
    },

    /**
     * If macro is defined in shader.
     * @param  {string} shaderType Can be vertex, fragment or both
     * @param  {string} symbol
     */
    isDefined: function (shaderType, symbol) {
        // PENDING hasOwnProperty ?
        switch (shaderType) {
            case 'vertex':
                return this.vertexDefines[symbol] !== undefined;
            case 'fragment':
                return this.fragmentDefines[symbol] !== undefined;
        }
    },
    /**
     * Get macro value defined in shader.
     * @param  {string} shaderType Can be vertex, fragment or both
     * @param  {string} symbol
     */
    getDefine: function (shaderType, symbol) {
        switch(shaderType) {
            case 'vertex':
                return this.vertexDefines[symbol];
            case 'fragment':
                return this.fragmentDefines[symbol];
        }
    },
    /**
     * Enable a texture, actually it will add a #define macro in the shader code
     * For example, if texture symbol is diffuseMap, it will add a line `#define DIFFUSEMAP_ENABLED` in the shader code
     * @param  {string} symbol
     */
    enableTexture: function (symbol) {
        if (Array.isArray(symbol)) {
            for (var i = 0; i < symbol.length; i++) {
                this.enableTexture(symbol[i]);
            }
            return;
        }

        var status = this._textureStatus[symbol];
        if (status) {
            var isEnabled = status.enabled;
            if (!isEnabled) {
                status.enabled = true;
                this._programKey = '';
            }
        }
    },
    /**
     * Enable all textures used in the shader
     */
    enableTexturesAll: function () {
        var textureStatus = this._textureStatus;
        for (var symbol in textureStatus) {
            textureStatus[symbol].enabled = true;
        }

        this._programKey = '';
    },
    /**
     * Disable a texture, it remove a #define macro in the shader
     * @param  {string} symbol
     */
    disableTexture: function (symbol) {
        if (Array.isArray(symbol)) {
            for (var i = 0; i < symbol.length; i++) {
                this.disableTexture(symbol[i]);
            }
            return;
        }

        var status = this._textureStatus[symbol];
        if (status) {
            var isDisabled = ! status.enabled;
            if (!isDisabled) {
                status.enabled = false;
                this._programKey = '';
            }
        }
    },
    /**
     * Disable all textures used in the shader
     */
    disableTexturesAll: function () {
        var textureStatus = this._textureStatus;
        for (var symbol in textureStatus) {
            textureStatus[symbol].enabled = false;
        }

        this._programKey = '';
    },
    /**
     * If texture of given type is enabled.
     * @param  {string}  symbol
     * @return {boolean}
     */
    isTextureEnabled: function (symbol) {
        var textureStatus = this._textureStatus;
        return !!textureStatus[symbol]
            && textureStatus[symbol].enabled;
    },

    /**
     * Get all enabled textures
     * @return {string[]}
     */
    getEnabledTextures: function () {
        var enabledTextures = [];
        var textureStatus = this._textureStatus;
        for (var symbol in textureStatus) {
            if (textureStatus[symbol].enabled) {
                enabledTextures.push(symbol);
            }
        }
        return enabledTextures;
    },

    /**
     * Mark defines are updated.
     */
    dirtyDefines: function () {
        this._programKey = '';
    },

    getProgramKey: function () {
        if (!this._programKey) {
            this._programKey = getProgramKey(
                this.vertexDefines, this.fragmentDefines, this.getEnabledTextures()
            );
        }
        return this._programKey;
    }
});

/* harmony default export */ const src_Material = (Material);

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/common.js

var GLMAT_EPSILON = 0.000001;

// Use Array instead of Float32Array. It seems to be much faster and higher precision.
var GLMAT_ARRAY_TYPE = Array;
// if(!GLMAT_ARRAY_TYPE) {
//     GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array;
// }

var common_GLMAT_RANDOM = Math.random;

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec2.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 2 Dimensional Vector
 * @name vec2
 */

var vec2 = {};

/**
 * Creates a new, empty vec2
 *
 * @returns {vec2} a new 2D vector
 */
vec2.create = function() {
    var out = new GLMAT_ARRAY_TYPE(2);
    out[0] = 0;
    out[1] = 0;
    return out;
};

/**
 * Creates a new vec2 initialized with values from an existing vector
 *
 * @param {vec2} a vector to clone
 * @returns {vec2} a new 2D vector
 */
vec2.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(2);
    out[0] = a[0];
    out[1] = a[1];
    return out;
};

/**
 * Creates a new vec2 initialized with the given values
 *
 * @param {Number} x X component
 * @param {Number} y Y component
 * @returns {vec2} a new 2D vector
 */
vec2.fromValues = function(x, y) {
    var out = new GLMAT_ARRAY_TYPE(2);
    out[0] = x;
    out[1] = y;
    return out;
};

/**
 * Copy the values from one vec2 to another
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the source vector
 * @returns {vec2} out
 */
vec2.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    return out;
};

/**
 * Set the components of a vec2 to the given values
 *
 * @param {vec2} out the receiving vector
 * @param {Number} x X component
 * @param {Number} y Y component
 * @returns {vec2} out
 */
vec2.set = function(out, x, y) {
    out[0] = x;
    out[1] = y;
    return out;
};

/**
 * Adds two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.add = function(out, a, b) {
    out[0] = a[0] + b[0];
    out[1] = a[1] + b[1];
    return out;
};

/**
 * Subtracts vector b from vector a
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.subtract = function(out, a, b) {
    out[0] = a[0] - b[0];
    out[1] = a[1] - b[1];
    return out;
};

/**
 * Alias for {@link vec2.subtract}
 * @function
 */
vec2.sub = vec2.subtract;

/**
 * Multiplies two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.multiply = function(out, a, b) {
    out[0] = a[0] * b[0];
    out[1] = a[1] * b[1];
    return out;
};

/**
 * Alias for {@link vec2.multiply}
 * @function
 */
vec2.mul = vec2.multiply;

/**
 * Divides two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.divide = function(out, a, b) {
    out[0] = a[0] / b[0];
    out[1] = a[1] / b[1];
    return out;
};

/**
 * Alias for {@link vec2.divide}
 * @function
 */
vec2.div = vec2.divide;

/**
 * Returns the minimum of two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.min = function(out, a, b) {
    out[0] = Math.min(a[0], b[0]);
    out[1] = Math.min(a[1], b[1]);
    return out;
};

/**
 * Returns the maximum of two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec2} out
 */
vec2.max = function(out, a, b) {
    out[0] = Math.max(a[0], b[0]);
    out[1] = Math.max(a[1], b[1]);
    return out;
};

/**
 * Scales a vec2 by a scalar number
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the vector to scale
 * @param {Number} b amount to scale the vector by
 * @returns {vec2} out
 */
vec2.scale = function(out, a, b) {
    out[0] = a[0] * b;
    out[1] = a[1] * b;
    return out;
};

/**
 * Adds two vec2's after scaling the second operand by a scalar value
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @param {Number} scale the amount to scale b by before adding
 * @returns {vec2} out
 */
vec2.scaleAndAdd = function(out, a, b, scale) {
    out[0] = a[0] + (b[0] * scale);
    out[1] = a[1] + (b[1] * scale);
    return out;
};

/**
 * Calculates the euclidian distance between two vec2's
 *
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {Number} distance between a and b
 */
vec2.distance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1];
    return Math.sqrt(x*x + y*y);
};

/**
 * Alias for {@link vec2.distance}
 * @function
 */
vec2.dist = vec2.distance;

/**
 * Calculates the squared euclidian distance between two vec2's
 *
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {Number} squared distance between a and b
 */
vec2.squaredDistance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1];
    return x*x + y*y;
};

/**
 * Alias for {@link vec2.squaredDistance}
 * @function
 */
vec2.sqrDist = vec2.squaredDistance;

/**
 * Calculates the length of a vec2
 *
 * @param {vec2} a vector to calculate length of
 * @returns {Number} length of a
 */
vec2.length = function (a) {
    var x = a[0],
        y = a[1];
    return Math.sqrt(x*x + y*y);
};

/**
 * Alias for {@link vec2.length}
 * @function
 */
vec2.len = vec2.length;

/**
 * Calculates the squared length of a vec2
 *
 * @param {vec2} a vector to calculate squared length of
 * @returns {Number} squared length of a
 */
vec2.squaredLength = function (a) {
    var x = a[0],
        y = a[1];
    return x*x + y*y;
};

/**
 * Alias for {@link vec2.squaredLength}
 * @function
 */
vec2.sqrLen = vec2.squaredLength;

/**
 * Negates the components of a vec2
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a vector to negate
 * @returns {vec2} out
 */
vec2.negate = function(out, a) {
    out[0] = -a[0];
    out[1] = -a[1];
    return out;
};

/**
 * Returns the inverse of the components of a vec2
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a vector to invert
 * @returns {vec2} out
 */
vec2.inverse = function(out, a) {
  out[0] = 1.0 / a[0];
  out[1] = 1.0 / a[1];
  return out;
};

/**
 * Normalize a vec2
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a vector to normalize
 * @returns {vec2} out
 */
vec2.normalize = function(out, a) {
    var x = a[0],
        y = a[1];
    var len = x*x + y*y;
    if (len > 0) {
        //TODO: evaluate use of glm_invsqrt here?
        len = 1 / Math.sqrt(len);
        out[0] = a[0] * len;
        out[1] = a[1] * len;
    }
    return out;
};

/**
 * Calculates the dot product of two vec2's
 *
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {Number} dot product of a and b
 */
vec2.dot = function (a, b) {
    return a[0] * b[0] + a[1] * b[1];
};

/**
 * Computes the cross product of two vec2's
 * Note that the cross product must by definition produce a 3D vector
 *
 * @param {vec3} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @returns {vec3} out
 */
vec2.cross = function(out, a, b) {
    var z = a[0] * b[1] - a[1] * b[0];
    out[0] = out[1] = 0;
    out[2] = z;
    return out;
};

/**
 * Performs a linear interpolation between two vec2's
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the first operand
 * @param {vec2} b the second operand
 * @param {Number} t interpolation amount between the two inputs
 * @returns {vec2} out
 */
vec2.lerp = function (out, a, b, t) {
    var ax = a[0],
        ay = a[1];
    out[0] = ax + t * (b[0] - ax);
    out[1] = ay + t * (b[1] - ay);
    return out;
};

/**
 * Generates a random vector with the given scale
 *
 * @param {vec2} out the receiving vector
 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
 * @returns {vec2} out
 */
vec2.random = function (out, scale) {
    scale = scale || 1.0;
    var r = GLMAT_RANDOM() * 2.0 * Math.PI;
    out[0] = Math.cos(r) * scale;
    out[1] = Math.sin(r) * scale;
    return out;
};

/**
 * Transforms the vec2 with a mat2
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the vector to transform
 * @param {mat2} m matrix to transform with
 * @returns {vec2} out
 */
vec2.transformMat2 = function(out, a, m) {
    var x = a[0],
        y = a[1];
    out[0] = m[0] * x + m[2] * y;
    out[1] = m[1] * x + m[3] * y;
    return out;
};

/**
 * Transforms the vec2 with a mat2d
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the vector to transform
 * @param {mat2d} m matrix to transform with
 * @returns {vec2} out
 */
vec2.transformMat2d = function(out, a, m) {
    var x = a[0],
        y = a[1];
    out[0] = m[0] * x + m[2] * y + m[4];
    out[1] = m[1] * x + m[3] * y + m[5];
    return out;
};

/**
 * Transforms the vec2 with a mat3
 * 3rd vector component is implicitly '1'
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the vector to transform
 * @param {mat3} m matrix to transform with
 * @returns {vec2} out
 */
vec2.transformMat3 = function(out, a, m) {
    var x = a[0],
        y = a[1];
    out[0] = m[0] * x + m[3] * y + m[6];
    out[1] = m[1] * x + m[4] * y + m[7];
    return out;
};

/**
 * Transforms the vec2 with a mat4
 * 3rd vector component is implicitly '0'
 * 4th vector component is implicitly '1'
 *
 * @param {vec2} out the receiving vector
 * @param {vec2} a the vector to transform
 * @param {mat4} m matrix to transform with
 * @returns {vec2} out
 */
vec2.transformMat4 = function(out, a, m) {
    var x = a[0],
        y = a[1];
    out[0] = m[0] * x + m[4] * y + m[12];
    out[1] = m[1] * x + m[5] * y + m[13];
    return out;
};

/**
 * Perform some operation over an array of vec2s.
 *
 * @param {Array} a the array of vectors to iterate over
 * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
 * @param {Number} offset Number of elements to skip at the beginning of the array
 * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
 * @param {Function} fn Function to call for each vector in the array
 * @param {Object} [arg] additional argument to pass to fn
 * @returns {Array} a
 * @function
 */
vec2.forEach = (function() {
    var vec = vec2.create();

    return function(a, stride, offset, count, fn, arg) {
        var i, l;
        if(!stride) {
            stride = 2;
        }

        if(!offset) {
            offset = 0;
        }

        if(count) {
            l = Math.min((count * stride) + offset, a.length);
        } else {
            l = a.length;
        }

        for(i = offset; i < l; i += stride) {
            vec[0] = a[i]; vec[1] = a[i+1];
            fn(vec, vec, arg);
            a[i] = vec[0]; a[i+1] = vec[1];
        }

        return a;
    };
})();

/* harmony default export */ const glmatrix_vec2 = (vec2);
;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Vector2.js


/**
 * @constructor
 * @alias clay.Vector2
 * @param {number} x
 * @param {number} y
 */
var Vector2 = function(x, y) {

    x = x || 0;
    y = y || 0;

    /**
     * Storage of Vector2, read and write of x, y will change the values in array
     * All methods also operate on the array instead of x, y components
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Vector2#
     */
    this.array = glmatrix_vec2.fromValues(x, y);

    /**
     * Dirty flag is used by the Node to determine
     * if the matrix is updated to latest
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Vector2#
     */
    this._dirty = true;
};

Vector2.prototype = {

    constructor: Vector2,

    /**
     * Add b to self
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    add: function(b) {
        glmatrix_vec2.add(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set x and y components
     * @param  {number}  x
     * @param  {number}  y
     * @return {clay.Vector2}
     */
    set: function(x, y) {
        this.array[0] = x;
        this.array[1] = y;
        this._dirty = true;
        return this;
    },

    /**
     * Set x and y components from array
     * @param  {Float32Array|number[]} arr
     * @return {clay.Vector2}
     */
    setArray: function(arr) {
        this.array[0] = arr[0];
        this.array[1] = arr[1];

        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Vector2
     * @return {clay.Vector2}
     */
    clone: function() {
        return new Vector2(this.x, this.y);
    },

    /**
     * Copy x, y from b
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    copy: function(b) {
        glmatrix_vec2.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Cross product of self and b, written to a Vector3 out
     * @param  {clay.Vector3} out
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    cross: function(out, b) {
        glmatrix_vec2.cross(out.array, this.array, b.array);
        out._dirty = true;
        return this;
    },

    /**
     * Alias for distance
     * @param  {clay.Vector2} b
     * @return {number}
     */
    dist: function(b) {
        return glmatrix_vec2.dist(this.array, b.array);
    },

    /**
     * Distance between self and b
     * @param  {clay.Vector2} b
     * @return {number}
     */
    distance: function(b) {
        return glmatrix_vec2.distance(this.array, b.array);
    },

    /**
     * Alias for divide
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    div: function(b) {
        glmatrix_vec2.div(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Divide self by b
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    divide: function(b) {
        glmatrix_vec2.divide(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Dot product of self and b
     * @param  {clay.Vector2} b
     * @return {number}
     */
    dot: function(b) {
        return glmatrix_vec2.dot(this.array, b.array);
    },

    /**
     * Alias of length
     * @return {number}
     */
    len: function() {
        return glmatrix_vec2.len(this.array);
    },

    /**
     * Calculate the length
     * @return {number}
     */
    length: function() {
        return glmatrix_vec2.length(this.array);
    },

    /**
     * Linear interpolation between a and b
     * @param  {clay.Vector2} a
     * @param  {clay.Vector2} b
     * @param  {number}  t
     * @return {clay.Vector2}
     */
    lerp: function(a, b, t) {
        glmatrix_vec2.lerp(this.array, a.array, b.array, t);
        this._dirty = true;
        return this;
    },

    /**
     * Minimum of self and b
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    min: function(b) {
        glmatrix_vec2.min(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Maximum of self and b
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    max: function(b) {
        glmatrix_vec2.max(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiply
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    mul: function(b) {
        glmatrix_vec2.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Mutiply self and b
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    multiply: function(b) {
        glmatrix_vec2.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Negate self
     * @return {clay.Vector2}
     */
    negate: function() {
        glmatrix_vec2.negate(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Normalize self
     * @return {clay.Vector2}
     */
    normalize: function() {
        glmatrix_vec2.normalize(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Generate random x, y components with a given scale
     * @param  {number} scale
     * @return {clay.Vector2}
     */
    random: function(scale) {
        glmatrix_vec2.random(this.array, scale);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self
     * @param  {number}  scale
     * @return {clay.Vector2}
     */
    scale: function(s) {
        glmatrix_vec2.scale(this.array, this.array, s);
        this._dirty = true;
        return this;
    },

    /**
     * Scale b and add to self
     * @param  {clay.Vector2} b
     * @param  {number}  scale
     * @return {clay.Vector2}
     */
    scaleAndAdd: function(b, s) {
        glmatrix_vec2.scaleAndAdd(this.array, this.array, b.array, s);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for squaredDistance
     * @param  {clay.Vector2} b
     * @return {number}
     */
    sqrDist: function(b) {
        return glmatrix_vec2.sqrDist(this.array, b.array);
    },

    /**
     * Squared distance between self and b
     * @param  {clay.Vector2} b
     * @return {number}
     */
    squaredDistance: function(b) {
        return glmatrix_vec2.squaredDistance(this.array, b.array);
    },

    /**
     * Alias for squaredLength
     * @return {number}
     */
    sqrLen: function() {
        return glmatrix_vec2.sqrLen(this.array);
    },

    /**
     * Squared length of self
     * @return {number}
     */
    squaredLength: function() {
        return glmatrix_vec2.squaredLength(this.array);
    },

    /**
     * Alias for subtract
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    sub: function(b) {
        glmatrix_vec2.sub(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Subtract b from self
     * @param  {clay.Vector2} b
     * @return {clay.Vector2}
     */
    subtract: function(b) {
        glmatrix_vec2.subtract(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix2 m
     * @param  {clay.Matrix2} m
     * @return {clay.Vector2}
     */
    transformMat2: function(m) {
        glmatrix_vec2.transformMat2(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix2d m
     * @param  {clay.Matrix2d} m
     * @return {clay.Vector2}
     */
    transformMat2d: function(m) {
        glmatrix_vec2.transformMat2d(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix3 m
     * @param  {clay.Matrix3} m
     * @return {clay.Vector2}
     */
    transformMat3: function(m) {
        glmatrix_vec2.transformMat3(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix4 m
     * @param  {clay.Matrix4} m
     * @return {clay.Vector2}
     */
    transformMat4: function(m) {
        glmatrix_vec2.transformMat4(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

// Getter and Setter
if (Object.defineProperty) {

    var proto = Vector2.prototype;
    /**
     * @name x
     * @type {number}
     * @memberOf clay.Vector2
     * @instance
     */
    Object.defineProperty(proto, 'x', {
        get: function () {
            return this.array[0];
        },
        set: function (value) {
            this.array[0] = value;
            this._dirty = true;
        }
    });

    /**
     * @name y
     * @type {number}
     * @memberOf clay.Vector2
     * @instance
     */
    Object.defineProperty(proto, 'y', {
        get: function () {
            return this.array[1];
        },
        set: function (value) {
            this.array[1] = value;
            this._dirty = true;
        }
    });
}

// Supply methods that are not in place

/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.add = function(out, a, b) {
    glmatrix_vec2.add(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector2} out
 * @param  {number}  x
 * @param  {number}  y
 * @return {clay.Vector2}
 */
Vector2.set = function(out, x, y) {
    glmatrix_vec2.set(out.array, x, y);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.copy = function(out, b) {
    glmatrix_vec2.copy(out.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.cross = function(out, a, b) {
    glmatrix_vec2.cross(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {number}
 */
Vector2.dist = function(a, b) {
    return glmatrix_vec2.distance(a.array, b.array);
};
/**
 * @function
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {number}
 */
Vector2.distance = Vector2.dist;
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.div = function(out, a, b) {
    glmatrix_vec2.divide(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.divide = Vector2.div;
/**
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {number}
 */
Vector2.dot = function(a, b) {
    return glmatrix_vec2.dot(a.array, b.array);
};

/**
 * @param  {clay.Vector2} a
 * @return {number}
 */
Vector2.len = function(b) {
    return glmatrix_vec2.length(b.array);
};

// Vector2.length = Vector2.len;

/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @param  {number}  t
 * @return {clay.Vector2}
 */
Vector2.lerp = function(out, a, b, t) {
    glmatrix_vec2.lerp(out.array, a.array, b.array, t);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.min = function(out, a, b) {
    glmatrix_vec2.min(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.max = function(out, a, b) {
    glmatrix_vec2.max(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.mul = function(out, a, b) {
    glmatrix_vec2.multiply(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.multiply = Vector2.mul;
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @return {clay.Vector2}
 */
Vector2.negate = function(out, a) {
    glmatrix_vec2.negate(out.array, a.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @return {clay.Vector2}
 */
Vector2.normalize = function(out, a) {
    glmatrix_vec2.normalize(out.array, a.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {number}  scale
 * @return {clay.Vector2}
 */
Vector2.random = function(out, scale) {
    glmatrix_vec2.random(out.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {number}  scale
 * @return {clay.Vector2}
 */
Vector2.scale = function(out, a, scale) {
    glmatrix_vec2.scale(out.array, a.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @param  {number}  scale
 * @return {clay.Vector2}
 */
Vector2.scaleAndAdd = function(out, a, b, scale) {
    glmatrix_vec2.scaleAndAdd(out.array, a.array, b.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {number}
 */
Vector2.sqrDist = function(a, b) {
    return glmatrix_vec2.sqrDist(a.array, b.array);
};
/**
 * @function
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {number}
 */
Vector2.squaredDistance = Vector2.sqrDist;

/**
 * @param  {clay.Vector2} a
 * @return {number}
 */
Vector2.sqrLen = function(a) {
    return glmatrix_vec2.sqrLen(a.array);
};
/**
 * @function
 * @param  {clay.Vector2} a
 * @return {number}
 */
Vector2.squaredLength = Vector2.sqrLen;

/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.sub = function(out, a, b) {
    glmatrix_vec2.subtract(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Vector2} b
 * @return {clay.Vector2}
 */
Vector2.subtract = Vector2.sub;
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Matrix2} m
 * @return {clay.Vector2}
 */
Vector2.transformMat2 = function(out, a, m) {
    glmatrix_vec2.transformMat2(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2}  out
 * @param  {clay.Vector2}  a
 * @param  {clay.Matrix2d} m
 * @return {clay.Vector2}
 */
Vector2.transformMat2d = function(out, a, m) {
    glmatrix_vec2.transformMat2d(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {Matrix3} m
 * @return {clay.Vector2}
 */
Vector2.transformMat3 = function(out, a, m) {
    glmatrix_vec2.transformMat3(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector2} out
 * @param  {clay.Vector2} a
 * @param  {clay.Matrix4} m
 * @return {clay.Vector2}
 */
Vector2.transformMat4 = function(out, a, m) {
    glmatrix_vec2.transformMat4(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Vector2 = (Vector2);

;// CONCATENATED MODULE: ./node_modules/claygl/src/gpu/GLProgram.js



var SHADER_STATE_TO_ENABLE = 1;
var SHADER_STATE_KEEP_ENABLE = 2;
var SHADER_STATE_PENDING = 3;

// Enable attribute operation is global to all programs
// Here saved the list of all enabled attribute index
// http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html
var enabledAttributeList = {};

// some util functions
function addLineNumbers(string) {
    var chunks = string.split('\n');
    for (var i = 0, il = chunks.length; i < il; i ++) {
        // Chrome reports shader errors on lines
        // starting counting from 1
        chunks[i] = (i + 1) + ': ' + chunks[i];
    }
    return chunks.join('\n');
}

// Return true or error msg if error happened
function checkShaderErrorMsg(_gl, shader, shaderString) {
    if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS)) {
        return [_gl.getShaderInfoLog(shader), addLineNumbers(shaderString)].join('\n');
    }
}

var tmpFloat32Array16 = new core_vendor.Float32Array(16);

var GLProgram = core_Base.extend({

    uniformSemantics: {},
    attributes: {}

}, function () {
    this._locations = {};

    this._textureSlot = 0;

    this._program = null;
}, {

    bind: function (renderer) {
        this._textureSlot = 0;
        renderer.gl.useProgram(this._program);
    },

    hasUniform: function (symbol) {
        var location = this._locations[symbol];
        return location !== null && location !== undefined;
    },

    useTextureSlot: function (renderer, texture, slot) {
        if (texture) {
            renderer.gl.activeTexture(renderer.gl.TEXTURE0 + slot);
            // Maybe texture is not loaded yet;
            if (texture.isRenderable()) {
                texture.bind(renderer);
            }
            else {
                // Bind texture to null
                texture.unbind(renderer);
            }
        }
    },

    currentTextureSlot: function () {
        return this._textureSlot;
    },

    resetTextureSlot: function (slot) {
        this._textureSlot = slot || 0;
    },

    takeCurrentTextureSlot: function (renderer, texture) {
        var textureSlot = this._textureSlot;

        this.useTextureSlot(renderer, texture, textureSlot);

        this._textureSlot++;

        return textureSlot;
    },

    setUniform: function (_gl, type, symbol, value) {
        var locationMap = this._locations;
        var location = locationMap[symbol];
        // Uniform is not existed in the shader
        if (location === null || location === undefined) {
            return false;
        }

        switch (type) {
            case 'm4':
                if (!(value instanceof Float32Array)) {
                    // Use Float32Array is much faster than array when uniformMatrix4fv.
                    for (var i = 0; i < value.length; i++) {
                        tmpFloat32Array16[i] = value[i];
                    }
                    value = tmpFloat32Array16;
                }
                _gl.uniformMatrix4fv(location, false, value);
                break;
            case '2i':
                _gl.uniform2i(location, value[0], value[1]);
                break;
            case '2f':
                _gl.uniform2f(location, value[0], value[1]);
                break;
            case '3i':
                _gl.uniform3i(location, value[0], value[1], value[2]);
                break;
            case '3f':
                _gl.uniform3f(location, value[0], value[1], value[2]);
                break;
            case '4i':
                _gl.uniform4i(location, value[0], value[1], value[2], value[3]);
                break;
            case '4f':
                _gl.uniform4f(location, value[0], value[1], value[2], value[3]);
                break;
            case '1i':
                _gl.uniform1i(location, value);
                break;
            case '1f':
                _gl.uniform1f(location, value);
                break;
            case '1fv':
                _gl.uniform1fv(location, value);
                break;
            case '1iv':
                _gl.uniform1iv(location, value);
                break;
            case '2iv':
                _gl.uniform2iv(location, value);
                break;
            case '2fv':
                _gl.uniform2fv(location, value);
                break;
            case '3iv':
                _gl.uniform3iv(location, value);
                break;
            case '3fv':
                _gl.uniform3fv(location, value);
                break;
            case '4iv':
                _gl.uniform4iv(location, value);
                break;
            case '4fv':
                _gl.uniform4fv(location, value);
                break;
            case 'm2':
            case 'm2v':
                _gl.uniformMatrix2fv(location, false, value);
                break;
            case 'm3':
            case 'm3v':
                _gl.uniformMatrix3fv(location, false, value);
                break;
            case 'm4v':
                // Raw value
                if (Array.isArray(value) && Array.isArray(value[0])) {
                    var array = new core_vendor.Float32Array(value.length * 16);
                    var cursor = 0;
                    for (var i = 0; i < value.length; i++) {
                        var item = value[i];
                        for (var j = 0; j < 16; j++) {
                            array[cursor++] = item[j];
                        }
                    }
                    _gl.uniformMatrix4fv(location, false, array);
                }
                else {   // ArrayBufferView
                    _gl.uniformMatrix4fv(location, false, value);
                }
                break;
        }
        return true;
    },

    setUniformOfSemantic: function (_gl, semantic, val) {
        var semanticInfo = this.uniformSemantics[semantic];
        if (semanticInfo) {
            return this.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, val);
        }
        return false;
    },

    // Used for creating VAO
    // Enable the attributes passed in and disable the rest
    // Example Usage:
    // enableAttributes(renderer, ["position", "texcoords"])
    enableAttributes: function (renderer, attribList, vao) {
        var _gl = renderer.gl;
        var program = this._program;

        var locationMap = this._locations;

        var enabledAttributeListInContext;
        if (vao) {
            enabledAttributeListInContext = vao.__enabledAttributeList;
        }
        else {
            enabledAttributeListInContext = enabledAttributeList[renderer.__uid__];
        }
        if (!enabledAttributeListInContext) {
            // In vertex array object context
            // PENDING Each vao object needs to enable attributes again?
            if (vao) {
                enabledAttributeListInContext
                    = vao.__enabledAttributeList
                    = [];
            }
            else {
                enabledAttributeListInContext
                    = enabledAttributeList[renderer.__uid__]
                    = [];
            }
        }
        var locationList = [];
        for (var i = 0; i < attribList.length; i++) {
            var symbol = attribList[i];
            if (!this.attributes[symbol]) {
                locationList[i] = -1;
                continue;
            }
            var location = locationMap[symbol];
            if (location == null) {
                location = _gl.getAttribLocation(program, symbol);
                // Attrib location is a number from 0 to ...
                if (location === -1) {
                    locationList[i] = -1;
                    continue;
                }
                locationMap[symbol] = location;
            }
            locationList[i] = location;

            if (!enabledAttributeListInContext[location]) {
                enabledAttributeListInContext[location] = SHADER_STATE_TO_ENABLE;
            }
            else {
                enabledAttributeListInContext[location] = SHADER_STATE_KEEP_ENABLE;
            }
        }

        for (var i = 0; i < enabledAttributeListInContext.length; i++) {
            switch(enabledAttributeListInContext[i]){
                case SHADER_STATE_TO_ENABLE:
                    _gl.enableVertexAttribArray(i);
                    enabledAttributeListInContext[i] = SHADER_STATE_PENDING;
                    break;
                case SHADER_STATE_KEEP_ENABLE:
                    enabledAttributeListInContext[i] = SHADER_STATE_PENDING;
                    break;
                // Expired
                case SHADER_STATE_PENDING:
                    _gl.disableVertexAttribArray(i);
                    enabledAttributeListInContext[i] = 0;
                    break;
            }
        }

        return locationList;
    },

    getAttribLocation: function (_gl, symbol) {
        var locationMap = this._locations;

        var location = locationMap[symbol];
        if (location == null) {
            location = _gl.getAttribLocation(this._program, symbol);
            locationMap[symbol] = location;
        }

        return location;
    },

    buildProgram: function (_gl, shader, vertexShaderCode, fragmentShaderCode) {
        var vertexShader = _gl.createShader(_gl.VERTEX_SHADER);
        var program = _gl.createProgram();

        _gl.shaderSource(vertexShader, vertexShaderCode);
        _gl.compileShader(vertexShader);

        var fragmentShader = _gl.createShader(_gl.FRAGMENT_SHADER);
        _gl.shaderSource(fragmentShader, fragmentShaderCode);
        _gl.compileShader(fragmentShader);

        var msg = checkShaderErrorMsg(_gl, vertexShader, vertexShaderCode);
        if (msg) {
            return msg;
        }
        msg = checkShaderErrorMsg(_gl, fragmentShader, fragmentShaderCode);
        if (msg) {
            return msg;
        }

        _gl.attachShader(program, vertexShader);
        _gl.attachShader(program, fragmentShader);
        // Force the position bind to location 0;
        if (shader.attributeSemantics['POSITION']) {
            _gl.bindAttribLocation(program, 0, shader.attributeSemantics['POSITION'].symbol);
        }
        else {
            // Else choose an attribute and bind to location 0;
            var keys = Object.keys(this.attributes);
            _gl.bindAttribLocation(program, 0, keys[0]);
        }

        _gl.linkProgram(program);

        _gl.deleteShader(vertexShader);
        _gl.deleteShader(fragmentShader);

        this._program = program;

        // Save code.
        this.vertexCode = vertexShaderCode;
        this.fragmentCode = fragmentShaderCode;

        if (!_gl.getProgramParameter(program, _gl.LINK_STATUS)) {
            return 'Could not link program\n' + _gl.getProgramInfoLog(program);
        }

        // Cache uniform locations
        for (var i = 0; i < shader.uniforms.length; i++) {
            var uniformSymbol = shader.uniforms[i];
            this._locations[uniformSymbol] = _gl.getUniformLocation(program, uniformSymbol);
        }

    }
});

/* harmony default export */ const gpu_GLProgram = (GLProgram);
;// CONCATENATED MODULE: ./node_modules/claygl/src/gpu/ProgramManager.js


var loopRegex = /for\s*?\(int\s*?_idx_\s*\=\s*([\w-]+)\;\s*_idx_\s*<\s*([\w-]+);\s*_idx_\s*\+\+\s*\)\s*\{\{([\s\S]+?)(?=\}\})\}\}/g;

function unrollLoop(shaderStr, defines, lightsNumbers) {
    // Loop unroll from three.js, https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProgram.js#L175
    // In some case like shadowMap in loop use 'i' to index value much slower.

    // Loop use _idx_ and increased with _idx_++ will be unrolled
    // Use {{ }} to match the pair so the if statement will not be affected
    // Write like following
    // for (int _idx_ = 0; _idx_ < 4; _idx_++) {{
    //     vec3 color = texture2D(textures[_idx_], uv).rgb;
    // }}
    function replace(match, start, end, snippet) {
        var unroll = '';
        // Try to treat as define
        if (isNaN(start)) {
            if (start in defines) {
                start = defines[start];
            }
            else {
                start = lightNumberDefines[start];
            }
        }
        if (isNaN(end)) {
            if (end in defines) {
                end = defines[end];
            }
            else {
                end = lightNumberDefines[end];
            }
        }
        // TODO Error checking

        for (var idx = parseInt(start); idx < parseInt(end); idx++) {
            // PENDING Add scope?
            unroll += '{'
                + snippet
                    .replace(/float\s*\(\s*_idx_\s*\)/g, idx.toFixed(1))
                    .replace(/_idx_/g, idx)
            + '}';
        }

        return unroll;
    }

    var lightNumberDefines = {};
    for (var lightType in lightsNumbers) {
        lightNumberDefines[lightType + '_COUNT'] = lightsNumbers[lightType];
    }
    return shaderStr.replace(loopRegex, replace);
}

function ProgramManager_getDefineCode(defines, lightsNumbers, enabledTextures) {
    var defineStr = [];
    if (lightsNumbers) {
        for (var lightType in lightsNumbers) {
            var count = lightsNumbers[lightType];
            if (count > 0) {
                defineStr.push('#define ' + lightType.toUpperCase() + '_COUNT ' + count);
            }
        }
    }
    if (enabledTextures) {
        for (var i = 0; i < enabledTextures.length; i++) {
            var symbol = enabledTextures[i];
            defineStr.push('#define ' + symbol.toUpperCase() + '_ENABLED');
        }
    }
    // Custom Defines
    for (var symbol in defines) {
        var value = defines[symbol];
        if (value === null) {
            defineStr.push('#define ' + symbol);
        }
        else{
            defineStr.push('#define ' + symbol + ' ' + value.toString());
        }
    }
    return defineStr.join('\n');
}

function getExtensionCode(exts) {
    // Extension declaration must before all non-preprocessor codes
    // TODO vertex ? extension enum ?
    var extensionStr = [];
    for (var i = 0; i < exts.length; i++) {
        extensionStr.push('#extension GL_' + exts[i] + ' : enable');
    }
    return extensionStr.join('\n');
}

function getPrecisionCode(precision) {
    return ['precision', precision, 'float'].join(' ') + ';\n'
        + ['precision', precision, 'int'].join(' ') + ';\n'
        // depth texture may have precision problem on iOS device.
        + ['precision', precision, 'sampler2D'].join(' ') + ';\n';
}

function ProgramManager(renderer) {
    this._renderer = renderer;
    this._cache = {};
}

ProgramManager.prototype.getProgram = function (renderable, material, scene) {
    var cache = this._cache;

    var isSkinnedMesh = renderable.isSkinnedMesh && renderable.isSkinnedMesh();
    var isInstancedMesh = renderable.isInstancedMesh && renderable.isInstancedMesh();
    var key = 's' + material.shader.shaderID + 'm' + material.getProgramKey();
    if (scene) {
        key += 'se' + scene.getProgramKey(renderable.lightGroup);
    }
    if (isSkinnedMesh) {
        key += ',sk' + renderable.joints.length;
    }
    if (isInstancedMesh) {
        key += ',is';
    }
    var program = cache[key];

    if (program) {
        return program;
    }

    var lightsNumbers = scene ? scene.getLightsNumbers(renderable.lightGroup) : {};
    var renderer = this._renderer;
    var _gl = renderer.gl;
    var enabledTextures = material.getEnabledTextures();
    var extraDefineCode = '';
    if (isSkinnedMesh) {
        var skinDefines = {
            SKINNING: null,
            JOINT_COUNT: renderable.joints.length
        };
        if (renderable.joints.length > renderer.getMaxJointNumber()) {
            skinDefines.USE_SKIN_MATRICES_TEXTURE = null;
        }
        // TODO Add skinning code?
        extraDefineCode += '\n' + ProgramManager_getDefineCode(skinDefines) + '\n';
    }
    if (isInstancedMesh) {
        extraDefineCode += '\n#define INSTANCING\n';
    }
    // TODO Optimize key generation
    // VERTEX
    var vertexDefineStr = extraDefineCode + ProgramManager_getDefineCode(material.vertexDefines, lightsNumbers, enabledTextures);
    // FRAGMENT
    var fragmentDefineStr = extraDefineCode + ProgramManager_getDefineCode(material.fragmentDefines, lightsNumbers, enabledTextures);

    var vertexCode = vertexDefineStr + '\n' + material.shader.vertex;

    var extensions = [
        'OES_standard_derivatives',
        'EXT_shader_texture_lod'
    ].filter(function (ext) {
        return renderer.getGLExtension(ext) != null;
    });

    if (extensions.indexOf('EXT_shader_texture_lod') >= 0) {
        fragmentDefineStr += '\n#define SUPPORT_TEXTURE_LOD';
    }
    if (extensions.indexOf('OES_standard_derivatives') >= 0) {
        fragmentDefineStr += '\n#define SUPPORT_STANDARD_DERIVATIVES';
    }

    var fragmentCode = getExtensionCode(extensions) + '\n'
        + getPrecisionCode(material.precision) + '\n'
        + fragmentDefineStr + '\n'
        + material.shader.fragment;

    var finalVertexCode = unrollLoop(vertexCode, material.vertexDefines, lightsNumbers);
    var finalFragmentCode = unrollLoop(fragmentCode, material.fragmentDefines, lightsNumbers);

    var program = new gpu_GLProgram();
    program.uniformSemantics = material.shader.uniformSemantics;
    program.attributes = material.shader.attributes;
    var errorMsg = program.buildProgram(_gl, material.shader, finalVertexCode, finalFragmentCode);
    program.__error = errorMsg;

    cache[key] = program;

    return program;
};

/* harmony default export */ const gpu_ProgramManager = (ProgramManager);
;// CONCATENATED MODULE: ./node_modules/claygl/src/Shader.js
/**
 * Mainly do the parse and compile of shader string
 * Support shader code chunk import and export
 * Support shader semantics
 * http://www.nvidia.com/object/using_sas.html
 * https://github.com/KhronosGroup/collada2json/issues/45
 */



var uniformRegex = /uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\s\S]*?);/g;
var attributeRegex = /attribute\s+(float|int|vec2|vec3|vec4)\s+([\s\S]*?);/g;
// Only parse number define.
var defineRegex = /#define\s+(\w+)?(\s+[\d-.]+)?\s*;?\s*\n/g;

var uniformTypeMap = {
    'bool': '1i',
    'int': '1i',
    'sampler2D': 't',
    'samplerCube': 't',
    'float': '1f',
    'vec2': '2f',
    'vec3': '3f',
    'vec4': '4f',
    'ivec2': '2i',
    'ivec3': '3i',
    'ivec4': '4i',
    'mat2': 'm2',
    'mat3': 'm3',
    'mat4': 'm4'
};

function createZeroArray(len) {
    var arr = [];
    for (var i = 0; i < len; i++) {
        arr[i] = 0;
    }
    return arr;
}

var uniformValueConstructor = {
    'bool': function () { return true; },
    'int': function () { return 0; },
    'float': function () { return 0; },
    'sampler2D': function () { return null; },
    'samplerCube': function () { return null; },

    'vec2': function () { return createZeroArray(2); },
    'vec3': function () { return createZeroArray(3); },
    'vec4': function () { return createZeroArray(4); },

    'ivec2': function () { return createZeroArray(2); },
    'ivec3': function () { return createZeroArray(3); },
    'ivec4': function () { return createZeroArray(4); },

    'mat2': function () { return createZeroArray(4); },
    'mat3': function () { return createZeroArray(9); },
    'mat4': function () { return createZeroArray(16); },

    'array': function () { return []; }
};

var attributeSemantics = [
    'POSITION',
    'NORMAL',
    'BINORMAL',
    'TANGENT',
    'TEXCOORD',
    'TEXCOORD_0',
    'TEXCOORD_1',
    'COLOR',
    // Skinning
    // https://github.com/KhronosGroup/glTF/blob/master/specification/README.md#semantics
    'JOINT',
    'WEIGHT'
];
var uniformSemantics = [
    'SKIN_MATRIX',
    // Information about viewport
    'VIEWPORT_SIZE',
    'VIEWPORT',
    'DEVICEPIXELRATIO',
    // Window size for window relative coordinate
    // https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml
    'WINDOW_SIZE',
    // Infomation about camera
    'NEAR',
    'FAR',
    // Time
    'TIME'
];
var matrixSemantics = [
    'WORLD',
    'VIEW',
    'PROJECTION',
    'WORLDVIEW',
    'VIEWPROJECTION',
    'WORLDVIEWPROJECTION',
    'WORLDINVERSE',
    'VIEWINVERSE',
    'PROJECTIONINVERSE',
    'WORLDVIEWINVERSE',
    'VIEWPROJECTIONINVERSE',
    'WORLDVIEWPROJECTIONINVERSE',
    'WORLDTRANSPOSE',
    'VIEWTRANSPOSE',
    'PROJECTIONTRANSPOSE',
    'WORLDVIEWTRANSPOSE',
    'VIEWPROJECTIONTRANSPOSE',
    'WORLDVIEWPROJECTIONTRANSPOSE',
    'WORLDINVERSETRANSPOSE',
    'VIEWINVERSETRANSPOSE',
    'PROJECTIONINVERSETRANSPOSE',
    'WORLDVIEWINVERSETRANSPOSE',
    'VIEWPROJECTIONINVERSETRANSPOSE',
    'WORLDVIEWPROJECTIONINVERSETRANSPOSE'
];

var attributeSizeMap = {
    // WebGL does not support integer attributes
    'vec4': 4,
    'vec3': 3,
    'vec2': 2,
    'float': 1
};


var shaderIDCache = {};
var shaderCodeCache = {};

function getShaderID(vertex, fragment) {
    var key = 'vertex:' + vertex + 'fragment:' + fragment;
    if (shaderIDCache[key]) {
        return shaderIDCache[key];
    }
    var id = core_util.genGUID();
    shaderIDCache[key] = id;

    shaderCodeCache[id] = {
        vertex: vertex,
        fragment: fragment
    };

    return id;
}

function removeComment(code) {
    return code.replace(/[ \t]*\/\/.*\n/g, '' )   // remove //
        .replace(/[ \t]*\/\*[\s\S]*?\*\//g, '' ); // remove /* */
}

function logSyntaxError() {
    console.error('Wrong uniform/attributes syntax');
}

function parseDeclarations(type, line) {
    var speratorsRegexp = /[,=\(\):]/;
    var tokens = line
        // Convert `symbol: [1,2,3]` to `symbol: vec3(1,2,3)`
        .replace(/:\s*\[\s*(.*)\s*\]/g, '=' + type + '($1)')
        .replace(/\s+/g, '')
        .split(/(?=[,=\(\):])/g);

    var newTokens = [];
    for (var i = 0; i < tokens.length; i++) {
        if (tokens[i].match(speratorsRegexp)) {
            newTokens.push(
                tokens[i].charAt(0),
                tokens[i].slice(1)
            );
        }
        else {
            newTokens.push(tokens[i]);
        }
    }
    tokens = newTokens;

    var TYPE_SYMBOL = 0;
    var TYPE_ASSIGN = 1;
    var TYPE_VEC = 2;
    var TYPE_ARR = 3;
    var TYPE_SEMANTIC = 4;
    var TYPE_NORMAL = 5;

    var opType = TYPE_SYMBOL;
    var declarations = {};
    var declarationValue = null;
    var currentDeclaration;

    addSymbol(tokens[0]);

    function addSymbol(symbol) {
        if (!symbol) {
            logSyntaxError();
        }
        var arrResult = symbol.match(/\[(.*?)\]/);
        currentDeclaration = symbol.replace(/\[(.*?)\]/, '');
        declarations[currentDeclaration] = {};
        if (arrResult) {
            declarations[currentDeclaration].isArray = true;
            declarations[currentDeclaration].arraySize = arrResult[1];
        }
    }

    for (var i = 1; i < tokens.length; i++) {
        var token = tokens[i];
        if (!token) {   // Empty token;
            continue;
        }
        if (token === '=') {
            if (opType !== TYPE_SYMBOL
            && opType !== TYPE_ARR) {
                logSyntaxError();
                break;
            }
            opType = TYPE_ASSIGN;

            continue;
        }
        else if (token === ':') {
            opType = TYPE_SEMANTIC;

            continue;
        }
        else if (token === ',') {
            if (opType === TYPE_VEC) {
                if (!(declarationValue instanceof Array)) {
                    logSyntaxError();
                    break;
                }
                declarationValue.push(+tokens[++i]);
            }
            else {
                opType = TYPE_NORMAL;
            }

            continue;
        }
        else if (token === ')') {
            declarations[currentDeclaration].value = new core_vendor.Float32Array(declarationValue);
            declarationValue = null;
            opType = TYPE_NORMAL;
            continue;
        }
        else if (token === '(') {
            if (opType !== TYPE_VEC) {
                logSyntaxError();
                break;
            }
            if (!(declarationValue instanceof Array)) {
                logSyntaxError();
                break;
            }
            declarationValue.push(+tokens[++i]);
            continue;
        }
        else if (token.indexOf('vec') >= 0) {
            if (opType !== TYPE_ASSIGN
            // Compatitable with old syntax `symbol: [1,2,3]`
            && opType !== TYPE_SEMANTIC) {
                logSyntaxError();
                break;
            }
            opType = TYPE_VEC;
            declarationValue = [];
            continue;
        }
        else if (opType === TYPE_ASSIGN) {
            if (type === 'bool') {
                declarations[currentDeclaration].value = token === 'true';
            }
            else {
                declarations[currentDeclaration].value = parseFloat(token);
            }
            declarationValue = null;
            continue;
        }
        else if (opType === TYPE_SEMANTIC) {
            var semantic = token;
            if (attributeSemantics.indexOf(semantic) >= 0
                || uniformSemantics.indexOf(semantic) >= 0
                || matrixSemantics.indexOf(semantic) >= 0
            ) {
                declarations[currentDeclaration].semantic = semantic;
            }
            else if (semantic === 'ignore' || semantic === 'unconfigurable') {
                declarations[currentDeclaration].ignore = true;
            }
            else {
                // Try to parse as a default tvalue.
                if (type === 'bool') {
                    declarations[currentDeclaration].value = semantic === 'true';
                }
                else {
                    declarations[currentDeclaration].value = parseFloat(semantic);
                }
            }
            continue;
        }

        // treat as symbol.
        addSymbol(token);
        opType = TYPE_SYMBOL;
    }

    return declarations;
}


/**
 * @constructor
 * @extends clay.core.Base
 * @alias clay.Shader
 * @param {string} vertex
 * @param {string} fragment
 * @example
 * // Create a phong shader
 * var shader = new clay.Shader(
 *      clay.Shader.source('clay.standard.vertex'),
 *      clay.Shader.source('clay.standard.fragment')
 * );
 */
function Shader(vertex, fragment) {
    // First argument can be { vertex, fragment }
    if (typeof vertex === 'object') {
        fragment = vertex.fragment;
        vertex = vertex.vertex;
    }

    vertex = removeComment(vertex);
    fragment = removeComment(fragment);

    this._shaderID = getShaderID(vertex, fragment);

    this._vertexCode = Shader.parseImport(vertex);
    this._fragmentCode = Shader.parseImport(fragment);

    /**
     * @readOnly
     */
    this.attributeSemantics = {};
    /**
     * @readOnly
     */
    this.matrixSemantics = {};
    /**
     * @readOnly
     */
    this.uniformSemantics = {};
    /**
     * @readOnly
     */
    this.matrixSemanticKeys = [];
    /**
     * @readOnly
     */
    this.uniformTemplates = {};
    /**
     * @readOnly
     */
    this.attributes = {};
    /**
     * @readOnly
     */
    this.textures = {};
    /**
     * @readOnly
     */
    this.vertexDefines = {};
    /**
     * @readOnly
     */
    this.fragmentDefines = {};

    this._parseAttributes();
    this._parseUniforms();
    this._parseDefines();
}

Shader.prototype = {

    constructor: Shader,

    // Create a new uniform instance for material
    createUniforms: function () {
        var uniforms = {};

        for (var symbol in this.uniformTemplates){
            var uniformTpl = this.uniformTemplates[symbol];
            uniforms[symbol] = {
                type: uniformTpl.type,
                value: uniformTpl.value()
            };
        }

        return uniforms;
    },

    _parseImport: function () {
        this._vertexCode = Shader.parseImport(this.vertex);
        this._fragmentCode = Shader.parseImport(this.fragment);
    },

    _addSemanticUniform: function (symbol, uniformType, semantic) {
        // This case is only for SKIN_MATRIX
        // TODO
        if (attributeSemantics.indexOf(semantic) >= 0) {
            this.attributeSemantics[semantic] = {
                symbol: symbol,
                type: uniformType
            };
        }
        else if (matrixSemantics.indexOf(semantic) >= 0) {
            var isTranspose = false;
            var semanticNoTranspose = semantic;
            if (semantic.match(/TRANSPOSE$/)) {
                isTranspose = true;
                semanticNoTranspose = semantic.slice(0, -9);
            }
            this.matrixSemantics[semantic] = {
                symbol: symbol,
                type: uniformType,
                isTranspose: isTranspose,
                semanticNoTranspose: semanticNoTranspose
            };
        }
        else if (uniformSemantics.indexOf(semantic) >= 0) {
            this.uniformSemantics[semantic] = {
                symbol: symbol,
                type: uniformType
            };
        }
    },

    _addMaterialUniform: function (symbol, type, uniformType, defaultValueFunc, isArray, materialUniforms) {
        materialUniforms[symbol] = {
            type: uniformType,
            value: isArray ? uniformValueConstructor['array'] : (defaultValueFunc || uniformValueConstructor[type]),
            semantic: null
        };
    },

    _parseUniforms: function () {
        var uniforms = {};
        var self = this;
        var shaderType = 'vertex';
        this._uniformList = [];

        this._vertexCode = this._vertexCode.replace(uniformRegex, _uniformParser);
        shaderType = 'fragment';
        this._fragmentCode = this._fragmentCode.replace(uniformRegex, _uniformParser);

        self.matrixSemanticKeys = Object.keys(this.matrixSemantics);

        function makeDefaultValueFunc(value) {
            return value != null ? function () { return value; } : null;
        }

        function _uniformParser(str, type, content) {
            var declaredUniforms = parseDeclarations(type, content);
            var uniformMainStr = [];
            for (var symbol in declaredUniforms) {

                var uniformInfo = declaredUniforms[symbol];
                var semantic = uniformInfo.semantic;
                var tmpStr = symbol;
                var uniformType = uniformTypeMap[type];
                var defaultValueFunc = makeDefaultValueFunc(declaredUniforms[symbol].value);
                if (declaredUniforms[symbol].isArray) {
                    tmpStr += '[' + declaredUniforms[symbol].arraySize + ']';
                    uniformType += 'v';
                }

                uniformMainStr.push(tmpStr);

                self._uniformList.push(symbol);

                if (!uniformInfo.ignore) {
                    if (type === 'sampler2D' || type === 'samplerCube') {
                        // Texture is default disabled
                        self.textures[symbol] = {
                            shaderType: shaderType,
                            type: type
                        };
                    }

                    if (semantic) {
                        // TODO Should not declare multiple symbols if have semantic.
                        self._addSemanticUniform(symbol, uniformType, semantic);
                    }
                    else {
                        self._addMaterialUniform(
                            symbol, type, uniformType, defaultValueFunc,
                            declaredUniforms[symbol].isArray, uniforms
                        );
                    }
                }
            }
            return uniformMainStr.length > 0
                ? 'uniform ' + type + ' ' + uniformMainStr.join(',') + ';\n' : '';
        }

        this.uniformTemplates = uniforms;
    },

    _parseAttributes: function () {
        var attributes = {};
        var self = this;
        this._vertexCode = this._vertexCode.replace(attributeRegex, _attributeParser);

        function _attributeParser(str, type, content) {
            var declaredAttributes = parseDeclarations(type, content);

            var size = attributeSizeMap[type] || 1;
            var attributeMainStr = [];
            for (var symbol in declaredAttributes) {
                var semantic = declaredAttributes[symbol].semantic;
                attributes[symbol] = {
                    // TODO Can only be float
                    type: 'float',
                    size: size,
                    semantic: semantic || null
                };
                // TODO Should not declare multiple symbols if have semantic.
                if (semantic) {
                    if (attributeSemantics.indexOf(semantic) < 0) {
                        throw new Error('Unkown semantic "' + semantic + '"');
                    }
                    else {
                        self.attributeSemantics[semantic] = {
                            symbol: symbol,
                            type: type
                        };
                    }
                }
                attributeMainStr.push(symbol);
            }

            return 'attribute ' + type + ' ' + attributeMainStr.join(',') + ';\n';
        }

        this.attributes = attributes;
    },

    _parseDefines: function () {
        var self = this;
        var shaderType = 'vertex';
        this._vertexCode = this._vertexCode.replace(defineRegex, _defineParser);
        shaderType = 'fragment';
        this._fragmentCode = this._fragmentCode.replace(defineRegex, _defineParser);

        function _defineParser(str, symbol, value) {
            var defines = shaderType === 'vertex' ? self.vertexDefines : self.fragmentDefines;
            if (!defines[symbol]) { // Haven't been defined by user
                if (value === 'false') {
                    defines[symbol] = false;
                }
                else if (value === 'true') {
                    defines[symbol] = true;
                }
                else {
                    defines[symbol] = value
                        // If can parse to float
                        ? (isNaN(parseFloat(value)) ? value.trim() : parseFloat(value))
                        : null;
                }
            }
            return '';
        }
    },

    /**
     * Clone a new shader
     * @return {clay.Shader}
     */
    clone: function () {
        var code = shaderCodeCache[this._shaderID];
        var shader = new Shader(code.vertex, code.fragment);
        return shader;
    }
};

if (Object.defineProperty) {
    Object.defineProperty(Shader.prototype, 'shaderID', {
        get: function () {
            return this._shaderID;
        }
    });
    Object.defineProperty(Shader.prototype, 'vertex', {
        get: function () {
            return this._vertexCode;
        }
    });
    Object.defineProperty(Shader.prototype, 'fragment', {
        get: function () {
            return this._fragmentCode;
        }
    });
    Object.defineProperty(Shader.prototype, 'uniforms', {
        get: function () {
            return this._uniformList;
        }
    });
}

var importRegex = /(@import)\s*([0-9a-zA-Z_\-\.]*)/g;
Shader.parseImport = function (shaderStr) {
    shaderStr = shaderStr.replace(importRegex, function (str, importSymbol, importName) {
        var str = Shader.source(importName);
        if (str) {
            // Recursively parse
            return Shader.parseImport(str);
        }
        else {
            console.error('Shader chunk "' + importName + '" not existed in library');
            return '';
        }
    });
    return shaderStr;
};

var exportRegex = /(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g;

/**
 * Import shader source
 * @param  {string} shaderStr
 * @memberOf clay.Shader
 */
Shader['import'] = function (shaderStr) {
    shaderStr.replace(exportRegex, function (str, exportSymbol, exportName, code) {
        var code = code.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g, '');
        if (code) {
            var parts = exportName.split('.');
            var obj = Shader.codes;
            var i = 0;
            var key;
            while (i < parts.length - 1) {
                key = parts[i++];
                if (!obj[key]) {
                    obj[key] = {};
                }
                obj = obj[key];
            }
            key = parts[i];
            obj[key] = code;
        }
        return code;
    });
};

/**
 * Library to store all the loaded shader codes
 * @type {Object}
 * @readOnly
 * @memberOf clay.Shader
 */
Shader.codes = {};

/**
 * Get shader source
 * @param  {string} name
 * @return {string}
 */
Shader.source = function (name) {
    var parts = name.split('.');
    var obj = Shader.codes;
    var i = 0;
    while (obj && i < parts.length) {
        var key = parts[i++];
        obj = obj[key];
    }
    if (typeof obj !== 'string') {
        // FIXME Use default instead
        console.error('Shader "' + name + '" not existed in library');
        return '';
    }
    return obj;
};

/* harmony default export */ const src_Shader = (Shader);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/prez.glsl.js
/* harmony default export */ const prez_glsl = ("@export clay.prez.vertex\nuniform mat4 WVP : WORLDVIEWPROJECTION;\nattribute vec3 pos : POSITION;\nattribute vec2 uv : TEXCOORD_0;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\n@import clay.chunk.skinning_header\n@import clay.chunk.instancing_header\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec4 P = vec4(pos, 1.0);\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n P = skinMatrixWS * P;\n#endif\n#ifdef INSTANCING\n @import clay.chunk.instancing_matrix\n P = instanceMat * P;\n#endif\n gl_Position = WVP * P;\n v_Texcoord = uv * uvRepeat + uvOffset;\n}\n@end\n@export clay.prez.fragment\nuniform sampler2D alphaMap;\nuniform float alphaCutoff: 0.0;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n if (alphaCutoff > 0.0) {\n if (texture2D(alphaMap, v_Texcoord).a <= alphaCutoff) {\n discard;\n }\n }\n gl_FragColor = vec4(0.0,0.0,0.0,1.0);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat4.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 4x4 Matrix
 * @name mat4
 */

var mat4 = {};

/**
 * Creates a new identity mat4
 *
 * @returns {mat4} a new 4x4 matrix
 */
mat4.create = function() {
    var out = new GLMAT_ARRAY_TYPE(16);
    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;
};

/**
 * Creates a new mat4 initialized with values from an existing matrix
 *
 * @param {mat4} a matrix to clone
 * @returns {mat4} a new 4x4 matrix
 */
mat4.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(16);
    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;
};

/**
 * Copy the values from one mat4 to another
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the source matrix
 * @returns {mat4} out
 */
mat4.copy = function(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;
};

/**
 * Set a mat4 to the identity matrix
 *
 * @param {mat4} out the receiving matrix
 * @returns {mat4} out
 */
mat4.identity = function(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;
};

/**
 * Transpose the values of a mat4
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the source matrix
 * @returns {mat4} out
 */
mat4.transpose = function(out, a) {
    // If we are transposing ourselves we can skip a few steps but have to cache some values
    if (out === a) {
        var a01 = a[1], a02 = a[2], a03 = a[3],
            a12 = a[6], a13 = a[7],
            a23 = a[11];

        out[1] = a[4];
        out[2] = a[8];
        out[3] = a[12];
        out[4] = a01;
        out[6] = a[9];
        out[7] = a[13];
        out[8] = a02;
        out[9] = a12;
        out[11] = a[14];
        out[12] = a03;
        out[13] = a13;
        out[14] = a23;
    } else {
        out[0] = a[0];
        out[1] = a[4];
        out[2] = a[8];
        out[3] = a[12];
        out[4] = a[1];
        out[5] = a[5];
        out[6] = a[9];
        out[7] = a[13];
        out[8] = a[2];
        out[9] = a[6];
        out[10] = a[10];
        out[11] = a[14];
        out[12] = a[3];
        out[13] = a[7];
        out[14] = a[11];
        out[15] = a[15];
    }

    return out;
};

/**
 * Inverts a mat4
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the source matrix
 * @returns {mat4} out
 */
mat4.invert = function(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,

        // Calculate the determinant
        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;
};

/**
 * Calculates the adjugate of a mat4
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the source matrix
 * @returns {mat4} out
 */
mat4.adjoint = function(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];

    out[0]  =  (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
    out[1]  = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
    out[2]  =  (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
    out[3]  = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
    out[4]  = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
    out[5]  =  (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
    out[6]  = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
    out[7]  =  (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
    out[8]  =  (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
    out[9]  = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
    out[10] =  (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
    out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
    out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
    out[13] =  (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
    out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
    out[15] =  (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
    return out;
};

/**
 * Calculates the determinant of a mat4
 *
 * @param {mat4} a the source matrix
 * @returns {Number} determinant of a
 */
mat4.determinant = function (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;

    // Calculate the determinant
    return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
};

/**
 * Multiplies two mat4's
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the first operand
 * @param {mat4} b the second operand
 * @returns {mat4} out
 */
mat4.multiply = function (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];

    // Cache only the current line of the second matrix
    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;
};

/**
 * Multiplies two affine mat4's
 * Add by https://github.com/pissang
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the first operand
 * @param {mat4} b the second operand
 * @returns {mat4} out
 */
mat4.multiplyAffine = function (out, a, b) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[4], a11 = a[5], a12 = a[6],
        a20 = a[8], a21 = a[9], a22 = a[10],
        a30 = a[12], a31 = a[13], a32 = a[14];

    // Cache only the current line of the second matrix
    var b0  = b[0], b1 = b[1], b2 = b[2];
    out[0] = b0*a00 + b1*a10 + b2*a20;
    out[1] = b0*a01 + b1*a11 + b2*a21;
    out[2] = b0*a02 + b1*a12 + b2*a22;
    // out[3] = 0;

    b0 = b[4]; b1 = b[5]; b2 = b[6];
    out[4] = b0*a00 + b1*a10 + b2*a20;
    out[5] = b0*a01 + b1*a11 + b2*a21;
    out[6] = b0*a02 + b1*a12 + b2*a22;
    // out[7] = 0;

    b0 = b[8]; b1 = b[9]; b2 = b[10];
    out[8] = b0*a00 + b1*a10 + b2*a20;
    out[9] = b0*a01 + b1*a11 + b2*a21;
    out[10] = b0*a02 + b1*a12 + b2*a22;
    // out[11] = 0;

    b0 = b[12]; b1 = b[13]; b2 = b[14];
    out[12] = b0*a00 + b1*a10 + b2*a20 + a30;
    out[13] = b0*a01 + b1*a11 + b2*a21 + a31;
    out[14] = b0*a02 + b1*a12 + b2*a22 + a32;
    // out[15] = 1;
    return out;
};

/**
 * Alias for {@link mat4.multiply}
 * @function
 */
mat4.mul = mat4.multiply;

/**
 * Alias for {@link mat4.multiplyAffine}
 * @function
 */
mat4.mulAffine = mat4.multiplyAffine;
/**
 * Translate a mat4 by the given vector
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to translate
 * @param {vec3} v vector to translate by
 * @returns {mat4} out
 */
mat4.translate = function (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;
};

/**
 * Scales the mat4 by the dimensions in the given vec3
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to scale
 * @param {vec3} v the vec3 to scale the matrix by
 * @returns {mat4} out
 **/
mat4.scale = function(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;
};

/**
 * Rotates a mat4 by the given angle
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @param {vec3} axis the axis to rotate around
 * @returns {mat4} out
 */
mat4.rotate = function (out, a, rad, axis) {
    var x = axis[0], y = axis[1], z = axis[2],
        len = Math.sqrt(x * x + y * y + z * z),
        s, c, t,
        a00, a01, a02, a03,
        a10, a11, a12, a13,
        a20, a21, a22, a23,
        b00, b01, b02,
        b10, b11, b12,
        b20, b21, b22;

    if (Math.abs(len) < GLMAT_EPSILON) { return null; }

    len = 1 / len;
    x *= len;
    y *= len;
    z *= len;

    s = Math.sin(rad);
    c = Math.cos(rad);
    t = 1 - c;

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

    // Construct the elements of the rotation matrix
    b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
    b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
    b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;

    // Perform rotation-specific matrix multiplication
    out[0] = a00 * b00 + a10 * b01 + a20 * b02;
    out[1] = a01 * b00 + a11 * b01 + a21 * b02;
    out[2] = a02 * b00 + a12 * b01 + a22 * b02;
    out[3] = a03 * b00 + a13 * b01 + a23 * b02;
    out[4] = a00 * b10 + a10 * b11 + a20 * b12;
    out[5] = a01 * b10 + a11 * b11 + a21 * b12;
    out[6] = a02 * b10 + a12 * b11 + a22 * b12;
    out[7] = a03 * b10 + a13 * b11 + a23 * b12;
    out[8] = a00 * b20 + a10 * b21 + a20 * b22;
    out[9] = a01 * b20 + a11 * b21 + a21 * b22;
    out[10] = a02 * b20 + a12 * b21 + a22 * b22;
    out[11] = a03 * b20 + a13 * b21 + a23 * b22;

    if (a !== out) { // If the source and destination differ, copy the unchanged last row
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
    }
    return out;
};

/**
 * Rotates a matrix by the given angle around the X axis
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat4} out
 */
mat4.rotateX = function (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) { // If the source and destination differ, copy the unchanged rows
        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];
    }

    // Perform axis-specific matrix multiplication
    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;
};

/**
 * Rotates a matrix by the given angle around the Y axis
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat4} out
 */
mat4.rotateY = function (out, a, rad) {
    var s = Math.sin(rad),
        c = Math.cos(rad),
        a00 = a[0],
        a01 = a[1],
        a02 = a[2],
        a03 = a[3],
        a20 = a[8],
        a21 = a[9],
        a22 = a[10],
        a23 = a[11];

    if (a !== out) { // If the source and destination differ, copy the unchanged rows
        out[4]  = a[4];
        out[5]  = a[5];
        out[6]  = a[6];
        out[7]  = a[7];
        out[12] = a[12];
        out[13] = a[13];
        out[14] = a[14];
        out[15] = a[15];
    }

    // Perform axis-specific matrix multiplication
    out[0] = a00 * c - a20 * s;
    out[1] = a01 * c - a21 * s;
    out[2] = a02 * c - a22 * s;
    out[3] = a03 * c - a23 * s;
    out[8] = a00 * s + a20 * c;
    out[9] = a01 * s + a21 * c;
    out[10] = a02 * s + a22 * c;
    out[11] = a03 * s + a23 * c;
    return out;
};

/**
 * Rotates a matrix by the given angle around the Z axis
 *
 * @param {mat4} out the receiving matrix
 * @param {mat4} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat4} out
 */
mat4.rotateZ = function (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) { // If the source and destination differ, copy the unchanged last row
        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];
    }

    // Perform axis-specific matrix multiplication
    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;
};

/**
 * Creates a matrix from a quaternion rotation and vector translation
 * This is equivalent to (but much faster than):
 *
 *     mat4.identity(dest);
 *     mat4.translate(dest, vec);
 *     var quatMat = mat4.create();
 *     quat4.toMat4(quat, quatMat);
 *     mat4.multiply(dest, quatMat);
 *
 * @param {mat4} out mat4 receiving operation result
 * @param {quat4} q Rotation quaternion
 * @param {vec3} v Translation vector
 * @returns {mat4} out
 */
mat4.fromRotationTranslation = function (out, q, v) {
    // Quaternion math
    var x = q[0], y = q[1], z = q[2], w = q[3],
        x2 = x + x,
        y2 = y + y,
        z2 = z + z,

        xx = x * x2,
        xy = x * y2,
        xz = x * z2,
        yy = y * y2,
        yz = y * z2,
        zz = z * z2,
        wx = w * x2,
        wy = w * y2,
        wz = w * z2;

    out[0] = 1 - (yy + zz);
    out[1] = xy + wz;
    out[2] = xz - wy;
    out[3] = 0;
    out[4] = xy - wz;
    out[5] = 1 - (xx + zz);
    out[6] = yz + wx;
    out[7] = 0;
    out[8] = xz + wy;
    out[9] = yz - wx;
    out[10] = 1 - (xx + yy);
    out[11] = 0;
    out[12] = v[0];
    out[13] = v[1];
    out[14] = v[2];
    out[15] = 1;

    return out;
};

mat4.fromQuat = function (out, q) {
    var x = q[0], y = q[1], z = q[2], w = q[3],
        x2 = x + x,
        y2 = y + y,
        z2 = z + z,

        xx = x * x2,
        yx = y * x2,
        yy = y * y2,
        zx = z * x2,
        zy = z * y2,
        zz = z * z2,
        wx = w * x2,
        wy = w * y2,
        wz = w * z2;

    out[0] = 1 - yy - zz;
    out[1] = yx + wz;
    out[2] = zx - wy;
    out[3] = 0;

    out[4] = yx - wz;
    out[5] = 1 - xx - zz;
    out[6] = zy + wx;
    out[7] = 0;

    out[8] = zx + wy;
    out[9] = zy - wx;
    out[10] = 1 - xx - yy;
    out[11] = 0;

    out[12] = 0;
    out[13] = 0;
    out[14] = 0;
    out[15] = 1;

    return out;
};

/**
 * Generates a frustum matrix with the given bounds
 *
 * @param {mat4} out mat4 frustum matrix will be written into
 * @param {Number} left Left bound of the frustum
 * @param {Number} right Right bound of the frustum
 * @param {Number} bottom Bottom bound of the frustum
 * @param {Number} top Top bound of the frustum
 * @param {Number} near Near bound of the frustum
 * @param {Number} far Far bound of the frustum
 * @returns {mat4} out
 */
mat4.frustum = function (out, left, right, bottom, top, near, far) {
    var rl = 1 / (right - left),
        tb = 1 / (top - bottom),
        nf = 1 / (near - far);
    out[0] = (near * 2) * rl;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[5] = (near * 2) * tb;
    out[6] = 0;
    out[7] = 0;
    out[8] = (right + left) * rl;
    out[9] = (top + bottom) * tb;
    out[10] = (far + near) * nf;
    out[11] = -1;
    out[12] = 0;
    out[13] = 0;
    out[14] = (far * near * 2) * nf;
    out[15] = 0;
    return out;
};

/**
 * Generates a perspective projection matrix with the given bounds
 *
 * @param {mat4} out mat4 frustum matrix will be written into
 * @param {number} fovy Vertical field of view in radians
 * @param {number} aspect Aspect ratio. typically viewport width/height
 * @param {number} near Near bound of the frustum
 * @param {number} far Far bound of the frustum
 * @returns {mat4} out
 */
mat4.perspective = function (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;
};

/**
 * Generates a orthogonal projection matrix with the given bounds
 *
 * @param {mat4} out mat4 frustum matrix will be written into
 * @param {number} left Left bound of the frustum
 * @param {number} right Right bound of the frustum
 * @param {number} bottom Bottom bound of the frustum
 * @param {number} top Top bound of the frustum
 * @param {number} near Near bound of the frustum
 * @param {number} far Far bound of the frustum
 * @returns {mat4} out
 */
mat4.ortho = function (out, left, right, bottom, top, near, far) {
    var lr = 1 / (left - right),
        bt = 1 / (bottom - top),
        nf = 1 / (near - far);
    out[0] = -2 * lr;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 0;
    out[5] = -2 * bt;
    out[6] = 0;
    out[7] = 0;
    out[8] = 0;
    out[9] = 0;
    out[10] = 2 * nf;
    out[11] = 0;
    out[12] = (left + right) * lr;
    out[13] = (top + bottom) * bt;
    out[14] = (far + near) * nf;
    out[15] = 1;
    return out;
};

/**
 * Generates a look-at matrix with the given eye position, focal point, and up axis
 *
 * @param {mat4} out mat4 frustum matrix will be written into
 * @param {vec3} eye Position of the viewer
 * @param {vec3} center Point the viewer is looking at
 * @param {vec3} up vec3 pointing up
 * @returns {mat4} out
 */
mat4.lookAt = function (out, eye, center, up) {
    var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
        eyex = eye[0],
        eyey = eye[1],
        eyez = eye[2],
        upx = up[0],
        upy = up[1],
        upz = up[2],
        centerx = center[0],
        centery = center[1],
        centerz = center[2];

    if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
        Math.abs(eyey - centery) < GLMAT_EPSILON &&
        Math.abs(eyez - centerz) < GLMAT_EPSILON) {
        return mat4.identity(out);
    }

    z0 = eyex - centerx;
    z1 = eyey - centery;
    z2 = eyez - centerz;

    len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
    z0 *= len;
    z1 *= len;
    z2 *= len;

    x0 = upy * z2 - upz * z1;
    x1 = upz * z0 - upx * z2;
    x2 = upx * z1 - upy * z0;
    len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
    if (!len) {
        x0 = 0;
        x1 = 0;
        x2 = 0;
    } else {
        len = 1 / len;
        x0 *= len;
        x1 *= len;
        x2 *= len;
    }

    y0 = z1 * x2 - z2 * x1;
    y1 = z2 * x0 - z0 * x2;
    y2 = z0 * x1 - z1 * x0;

    len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
    if (!len) {
        y0 = 0;
        y1 = 0;
        y2 = 0;
    } else {
        len = 1 / len;
        y0 *= len;
        y1 *= len;
        y2 *= len;
    }

    out[0] = x0;
    out[1] = y0;
    out[2] = z0;
    out[3] = 0;
    out[4] = x1;
    out[5] = y1;
    out[6] = z1;
    out[7] = 0;
    out[8] = x2;
    out[9] = y2;
    out[10] = z2;
    out[11] = 0;
    out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
    out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
    out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
    out[15] = 1;

    return out;
};

/**
 * Returns Frobenius norm of a mat4
 *
 * @param {mat4} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat4.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) ))
};

/* harmony default export */ const glmatrix_mat4 = (mat4);
;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec3.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 3 Dimensional Vector
 * @name vec3
 */

var vec3 = {};

/**
 * Creates a new, empty vec3
 *
 * @returns {vec3} a new 3D vector
 */
vec3.create = function() {
    var out = new GLMAT_ARRAY_TYPE(3);
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    return out;
};

/**
 * Creates a new vec3 initialized with values from an existing vector
 *
 * @param {vec3} a vector to clone
 * @returns {vec3} a new 3D vector
 */
vec3.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(3);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    return out;
};

/**
 * Creates a new vec3 initialized with the given values
 *
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @returns {vec3} a new 3D vector
 */
vec3.fromValues = function(x, y, z) {
    var out = new GLMAT_ARRAY_TYPE(3);
    out[0] = x;
    out[1] = y;
    out[2] = z;
    return out;
};

/**
 * Copy the values from one vec3 to another
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the source vector
 * @returns {vec3} out
 */
vec3.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    return out;
};

/**
 * Set the components of a vec3 to the given values
 *
 * @param {vec3} out the receiving vector
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @returns {vec3} out
 */
vec3.set = function(out, x, y, z) {
    out[0] = x;
    out[1] = y;
    out[2] = z;
    return out;
};

/**
 * Adds two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.add = function(out, a, b) {
    out[0] = a[0] + b[0];
    out[1] = a[1] + b[1];
    out[2] = a[2] + b[2];
    return out;
};

/**
 * Subtracts vector b from vector a
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.subtract = function(out, a, b) {
    out[0] = a[0] - b[0];
    out[1] = a[1] - b[1];
    out[2] = a[2] - b[2];
    return out;
};

/**
 * Alias for {@link vec3.subtract}
 * @function
 */
vec3.sub = vec3.subtract;

/**
 * Multiplies two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.multiply = function(out, a, b) {
    out[0] = a[0] * b[0];
    out[1] = a[1] * b[1];
    out[2] = a[2] * b[2];
    return out;
};

/**
 * Alias for {@link vec3.multiply}
 * @function
 */
vec3.mul = vec3.multiply;

/**
 * Divides two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.divide = function(out, a, b) {
    out[0] = a[0] / b[0];
    out[1] = a[1] / b[1];
    out[2] = a[2] / b[2];
    return out;
};

/**
 * Alias for {@link vec3.divide}
 * @function
 */
vec3.div = vec3.divide;

/**
 * Returns the minimum of two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.min = function(out, a, b) {
    out[0] = Math.min(a[0], b[0]);
    out[1] = Math.min(a[1], b[1]);
    out[2] = Math.min(a[2], b[2]);
    return out;
};

/**
 * Returns the maximum of two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.max = function(out, a, b) {
    out[0] = Math.max(a[0], b[0]);
    out[1] = Math.max(a[1], b[1]);
    out[2] = Math.max(a[2], b[2]);
    return out;
};

/**
 * Scales a vec3 by a scalar number
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the vector to scale
 * @param {Number} b amount to scale the vector by
 * @returns {vec3} out
 */
vec3.scale = function(out, a, b) {
    out[0] = a[0] * b;
    out[1] = a[1] * b;
    out[2] = a[2] * b;
    return out;
};

/**
 * Adds two vec3's after scaling the second operand by a scalar value
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @param {Number} scale the amount to scale b by before adding
 * @returns {vec3} out
 */
vec3.scaleAndAdd = function(out, a, b, scale) {
    out[0] = a[0] + (b[0] * scale);
    out[1] = a[1] + (b[1] * scale);
    out[2] = a[2] + (b[2] * scale);
    return out;
};

/**
 * Calculates the euclidian distance between two vec3's
 *
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {Number} distance between a and b
 */
vec3.distance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1],
        z = b[2] - a[2];
    return Math.sqrt(x*x + y*y + z*z);
};

/**
 * Alias for {@link vec3.distance}
 * @function
 */
vec3.dist = vec3.distance;

/**
 * Calculates the squared euclidian distance between two vec3's
 *
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {Number} squared distance between a and b
 */
vec3.squaredDistance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1],
        z = b[2] - a[2];
    return x*x + y*y + z*z;
};

/**
 * Alias for {@link vec3.squaredDistance}
 * @function
 */
vec3.sqrDist = vec3.squaredDistance;

/**
 * Calculates the length of a vec3
 *
 * @param {vec3} a vector to calculate length of
 * @returns {Number} length of a
 */
vec3.length = function (a) {
    var x = a[0],
        y = a[1],
        z = a[2];
    return Math.sqrt(x*x + y*y + z*z);
};

/**
 * Alias for {@link vec3.length}
 * @function
 */
vec3.len = vec3.length;

/**
 * Calculates the squared length of a vec3
 *
 * @param {vec3} a vector to calculate squared length of
 * @returns {Number} squared length of a
 */
vec3.squaredLength = function (a) {
    var x = a[0],
        y = a[1],
        z = a[2];
    return x*x + y*y + z*z;
};

/**
 * Alias for {@link vec3.squaredLength}
 * @function
 */
vec3.sqrLen = vec3.squaredLength;

/**
 * Negates the components of a vec3
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a vector to negate
 * @returns {vec3} out
 */
vec3.negate = function(out, a) {
    out[0] = -a[0];
    out[1] = -a[1];
    out[2] = -a[2];
    return out;
};

/**
 * Returns the inverse of the components of a vec3
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a vector to invert
 * @returns {vec3} out
 */
vec3.inverse = function(out, a) {
  out[0] = 1.0 / a[0];
  out[1] = 1.0 / a[1];
  out[2] = 1.0 / a[2];
  return out;
};

/**
 * Normalize a vec3
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a vector to normalize
 * @returns {vec3} out
 */
vec3.normalize = function(out, a) {
    var x = a[0],
        y = a[1],
        z = a[2];
    var len = x*x + y*y + z*z;
    if (len > 0) {
        //TODO: evaluate use of glm_invsqrt here?
        len = 1 / Math.sqrt(len);
        out[0] = a[0] * len;
        out[1] = a[1] * len;
        out[2] = a[2] * len;
    }
    return out;
};

/**
 * Calculates the dot product of two vec3's
 *
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {Number} dot product of a and b
 */
vec3.dot = function (a, b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
};

/**
 * Computes the cross product of two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @returns {vec3} out
 */
vec3.cross = function(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;
};

/**
 * Performs a linear interpolation between two vec3's
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the first operand
 * @param {vec3} b the second operand
 * @param {Number} t interpolation amount between the two inputs
 * @returns {vec3} out
 */
vec3.lerp = function (out, a, b, t) {
    var ax = a[0],
        ay = a[1],
        az = a[2];
    out[0] = ax + t * (b[0] - ax);
    out[1] = ay + t * (b[1] - ay);
    out[2] = az + t * (b[2] - az);
    return out;
};

/**
 * Generates a random vector with the given scale
 *
 * @param {vec3} out the receiving vector
 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
 * @returns {vec3} out
 */
vec3.random = function (out, scale) {
    scale = scale || 1.0;

    var r = common_GLMAT_RANDOM() * 2.0 * Math.PI;
    var z = (common_GLMAT_RANDOM() * 2.0) - 1.0;
    var zScale = Math.sqrt(1.0-z*z) * scale;

    out[0] = Math.cos(r) * zScale;
    out[1] = Math.sin(r) * zScale;
    out[2] = z * scale;
    return out;
};

/**
 * Transforms the vec3 with a mat4.
 * 4th vector component is implicitly '1'
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the vector to transform
 * @param {mat4} m matrix to transform with
 * @returns {vec3} out
 */
vec3.transformMat4 = function(out, a, m) {
    var x = a[0], y = a[1], z = a[2],
        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;
};

/**
 * Transforms the vec3 with a mat3.
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the vector to transform
 * @param {mat4} m the 3x3 matrix to transform with
 * @returns {vec3} out
 */
vec3.transformMat3 = function(out, a, m) {
    var x = a[0], y = a[1], z = a[2];
    out[0] = x * m[0] + y * m[3] + z * m[6];
    out[1] = x * m[1] + y * m[4] + z * m[7];
    out[2] = x * m[2] + y * m[5] + z * m[8];
    return out;
};

/**
 * Transforms the vec3 with a quat
 *
 * @param {vec3} out the receiving vector
 * @param {vec3} a the vector to transform
 * @param {quat} q quaternion to transform with
 * @returns {vec3} out
 */
vec3.transformQuat = function(out, a, q) {
    // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations

    var x = a[0], y = a[1], z = a[2],
        qx = q[0], qy = q[1], qz = q[2], qw = q[3],

        // calculate quat * vec
        ix = qw * x + qy * z - qz * y,
        iy = qw * y + qz * x - qx * z,
        iz = qw * z + qx * y - qy * x,
        iw = -qx * x - qy * y - qz * z;

    // calculate result * inverse quat
    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
    return out;
};

/**
 * Rotate a 3D vector around the x-axis
 * @param {vec3} out The receiving vec3
 * @param {vec3} a The vec3 point to rotate
 * @param {vec3} b The origin of the rotation
 * @param {Number} c The angle of rotation
 * @returns {vec3} out
 */
vec3.rotateX = function(out, a, b, c){
   var p = [], r=[];
      //Translate point to the origin
      p[0] = a[0] - b[0];
      p[1] = a[1] - b[1];
    p[2] = a[2] - b[2];

      //perform rotation
      r[0] = p[0];
      r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c);
      r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c);

      //translate to correct position
      out[0] = r[0] + b[0];
      out[1] = r[1] + b[1];
      out[2] = r[2] + b[2];

    return out;
};

/**
 * Rotate a 3D vector around the y-axis
 * @param {vec3} out The receiving vec3
 * @param {vec3} a The vec3 point to rotate
 * @param {vec3} b The origin of the rotation
 * @param {Number} c The angle of rotation
 * @returns {vec3} out
 */
vec3.rotateY = function(out, a, b, c){
    var p = [], r=[];
    //Translate point to the origin
    p[0] = a[0] - b[0];
    p[1] = a[1] - b[1];
    p[2] = a[2] - b[2];

    //perform rotation
    r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c);
    r[1] = p[1];
    r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c);

    //translate to correct position
    out[0] = r[0] + b[0];
    out[1] = r[1] + b[1];
    out[2] = r[2] + b[2];

    return out;
};

/**
 * Rotate a 3D vector around the z-axis
 * @param {vec3} out The receiving vec3
 * @param {vec3} a The vec3 point to rotate
 * @param {vec3} b The origin of the rotation
 * @param {Number} c The angle of rotation
 * @returns {vec3} out
 */
vec3.rotateZ = function(out, a, b, c){
    var p = [], r=[];
    //Translate point to the origin
    p[0] = a[0] - b[0];
    p[1] = a[1] - b[1];
    p[2] = a[2] - b[2];

    //perform rotation
    r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c);
    r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c);
    r[2] = p[2];

    //translate to correct position
    out[0] = r[0] + b[0];
    out[1] = r[1] + b[1];
    out[2] = r[2] + b[2];

    return out;
};

/**
 * Perform some operation over an array of vec3s.
 *
 * @param {Array} a the array of vectors to iterate over
 * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
 * @param {Number} offset Number of elements to skip at the beginning of the array
 * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
 * @param {Function} fn Function to call for each vector in the array
 * @param {Object} [arg] additional argument to pass to fn
 * @returns {Array} a
 * @function
 */
vec3.forEach = (function() {
    var vec = vec3.create();

    return function(a, stride, offset, count, fn, arg) {
        var i, l;
        if(!stride) {
            stride = 3;
        }

        if(!offset) {
            offset = 0;
        }

        if(count) {
            l = Math.min((count * stride) + offset, a.length);
        } else {
            l = a.length;
        }

        for(i = offset; i < l; i += stride) {
            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
            fn(vec, vec, arg);
            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
        }

        return a;
    };
})();

/**
 * Get the angle between two 3D vectors
 * @param {vec3} a The first operand
 * @param {vec3} b The second operand
 * @returns {Number} The angle in radians
 */
vec3.angle = function(a, b) {

    var tempA = vec3.fromValues(a[0], a[1], a[2]);
    var tempB = vec3.fromValues(b[0], b[1], b[2]);

    vec3.normalize(tempA, tempA);
    vec3.normalize(tempB, tempB);

    var cosine = vec3.dot(tempA, tempB);

    if(cosine > 1.0){
        return 0;
    } else {
        return Math.acos(cosine);
    }
};

/* harmony default export */ const glmatrix_vec3 = (vec3);
;// CONCATENATED MODULE: ./node_modules/claygl/src/Renderer.js
// TODO Resources like shader, texture, geometry reference management
// Trace and find out which shader, texture, geometry can be destroyed









// Light header



src_Shader.import(prez_glsl);




var mat4Create = glmatrix_mat4.create;

var errorShader = {};

function defaultGetMaterial(renderable) {
    return renderable.material;
}
function defaultGetUniform(renderable, material, symbol) {
    return material.uniforms[symbol].value;
}
function defaultIsMaterialChanged(renderabled, prevRenderable, material, prevMaterial) {
    return material !== prevMaterial;
}
function defaultIfRender(renderable) {
    return true;
}

function noop() {}

var attributeBufferTypeMap = {
    float: glenum.FLOAT,
    byte: glenum.BYTE,
    ubyte: glenum.UNSIGNED_BYTE,
    short: glenum.SHORT,
    ushort: glenum.UNSIGNED_SHORT
};

function VertexArrayObject(availableAttributes, availableAttributeSymbols, indicesBuffer) {
    this.availableAttributes = availableAttributes;
    this.availableAttributeSymbols = availableAttributeSymbols;
    this.indicesBuffer = indicesBuffer;

    this.vao = null;
}

function PlaceHolderTexture(renderer) {
    var blankCanvas;
    var webglTexture;
    this.bind = function (renderer) {
        if (!blankCanvas) {
            // TODO Environment not support createCanvas.
            blankCanvas = core_vendor.createCanvas();
            blankCanvas.width = blankCanvas.height = 1;
            blankCanvas.getContext('2d');
        }

        var gl = renderer.gl;
        var firstBind = !webglTexture;
        if (firstBind) {
            webglTexture = gl.createTexture();
        }
        gl.bindTexture(gl.TEXTURE_2D, webglTexture);
        if (firstBind) {
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, blankCanvas);
        }
    };
    this.unbind = function (renderer) {
        renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, null);
    };
    this.isRenderable = function () {
        return true;
    };
}
/**
 * @constructor clay.Renderer
 * @extends clay.core.Base
 */
var Renderer = core_Base.extend(function () {
    return /** @lends clay.Renderer# */ {

        /**
         * @type {HTMLCanvasElement}
         * @readonly
         */
        canvas: null,

        /**
         * Canvas width, set by resize method
         * @type {number}
         * @private
         */
        _width: 100,

        /**
         * Canvas width, set by resize method
         * @type {number}
         * @private
         */
        _height: 100,

        /**
         * Device pixel ratio, set by setDevicePixelRatio method
         * Specially for high defination display
         * @see http://www.khronos.org/webgl/wiki/HandlingHighDPI
         * @type {number}
         * @private
         */
        devicePixelRatio: (typeof window !== 'undefined' && window.devicePixelRatio) || 1.0,

        /**
         * Clear color
         * @type {number[]}
         */
        clearColor: [0.0, 0.0, 0.0, 0.0],

        /**
         * Default:
         *     _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT
         * @type {number}
         */
        clearBit: 17664,

        // Settings when getting context
        // http://www.khronos.org/registry/webgl/specs/latest/#2.4

        /**
         * If enable alpha, default true
         * @type {boolean}
         */
        alpha: true,
        /**
         * If enable depth buffer, default true
         * @type {boolean}
         */
        depth: true,
        /**
         * If enable stencil buffer, default false
         * @type {boolean}
         */
        stencil: false,
        /**
         * If enable antialias, default true
         * @type {boolean}
         */
        antialias: true,
        /**
         * If enable premultiplied alpha, default true
         * @type {boolean}
         */
        premultipliedAlpha: true,
        /**
         * If preserve drawing buffer, default false
         * @type {boolean}
         */
        preserveDrawingBuffer: false,
        /**
         * If throw context error, usually turned on in debug mode
         * @type {boolean}
         */
        throwError: true,
        /**
         * WebGL Context created from given canvas
         * @type {WebGLRenderingContext}
         */
        gl: null,
        /**
         * Renderer viewport, read-only, can be set by setViewport method
         * @type {Object}
         */
        viewport: {},

        /**
         * Max joint number
         * @type {number}
         */
        maxJointNumber: 20,

        // Set by FrameBuffer#bind
        __currentFrameBuffer: null,

        _viewportStack: [],
        _clearStack: [],

        _sceneRendering: null
    };
}, function () {

    if (!this.canvas) {
        this.canvas = core_vendor.createCanvas();
    }
    var canvas = this.canvas;
    try {
        var opts = {
            alpha: this.alpha,
            depth: this.depth,
            stencil: this.stencil,
            antialias: this.antialias,
            premultipliedAlpha: this.premultipliedAlpha,
            preserveDrawingBuffer: this.preserveDrawingBuffer
        };

        this.gl = canvas.getContext('webgl', opts)
            || canvas.getContext('experimental-webgl', opts);

        if (!this.gl) {
            throw new Error();
        }

        this._glinfo = new core_GLInfo(this.gl);

        if (this.gl.targetRenderer) {
            console.error('Already created a renderer');
        }
        this.gl.targetRenderer = this;

        this.resize();
    }
    catch (e) {
        throw 'Error creating WebGL Context ' + e;
    }

    // Init managers
    this._programMgr = new gpu_ProgramManager(this);

    this._placeholderTexture = new PlaceHolderTexture(this);
},
/** @lends clay.Renderer.prototype. **/
{
    /**
     * Resize the canvas
     * @param {number} width
     * @param {number} height
     */
    resize: function(width, height) {
        var canvas = this.canvas;
        // http://www.khronos.org/webgl/wiki/HandlingHighDPI
        // set the display size of the canvas.
        var dpr = this.devicePixelRatio;
        if (width != null) {
            if (canvas.style) {
                canvas.style.width = width + 'px';
                canvas.style.height = height + 'px';
            }
            // set the size of the drawingBuffer
            canvas.width = width * dpr;
            canvas.height = height * dpr;

            this._width = width;
            this._height = height;
        }
        else {
            this._width = canvas.width / dpr;
            this._height = canvas.height / dpr;
        }

        this.setViewport(0, 0, this._width, this._height);
    },

    /**
     * Get renderer width
     * @return {number}
     */
    getWidth: function () {
        return this._width;
    },

    /**
     * Get renderer height
     * @return {number}
     */
    getHeight: function () {
        return this._height;
    },

    /**
     * Get viewport aspect,
     * @return {number}
     */
    getViewportAspect: function () {
        var viewport = this.viewport;
        return viewport.width / viewport.height;
    },

    /**
     * Set devicePixelRatio
     * @param {number} devicePixelRatio
     */
    setDevicePixelRatio: function(devicePixelRatio) {
        this.devicePixelRatio = devicePixelRatio;
        this.resize(this._width, this._height);
    },

    /**
     * Get devicePixelRatio
     * @param {number} devicePixelRatio
     */
    getDevicePixelRatio: function () {
        return this.devicePixelRatio;
    },

    /**
     * Get WebGL extension
     * @param {string} name
     * @return {object}
     */
    getGLExtension: function (name) {
        return this._glinfo.getExtension(name);
    },

    /**
     * Get WebGL parameter
     * @param {string} name
     * @return {*}
     */
    getGLParameter: function (name) {
        return this._glinfo.getParameter(name);
    },

    /**
     * Set rendering viewport
     * @param {number|Object} x
     * @param {number} [y]
     * @param {number} [width]
     * @param {number} [height]
     * @param {number} [devicePixelRatio]
     *        Defaultly use the renderere devicePixelRatio
     *        It needs to be 1 when setViewport is called by frameBuffer
     *
     * @example
     *  setViewport(0,0,width,height,1)
     *  setViewport({
     *      x: 0,
     *      y: 0,
     *      width: width,
     *      height: height,
     *      devicePixelRatio: 1
     *  })
     */
    setViewport: function (x, y, width, height, dpr) {

        if (typeof x === 'object') {
            var obj = x;

            x = obj.x;
            y = obj.y;
            width = obj.width;
            height = obj.height;
            dpr = obj.devicePixelRatio;
        }
        dpr = dpr || this.devicePixelRatio;

        this.gl.viewport(
            x * dpr, y * dpr, width * dpr, height * dpr
        );
        // Use a fresh new object, not write property.
        this.viewport = {
            x: x,
            y: y,
            width: width,
            height: height,
            devicePixelRatio: dpr
        };
    },

    /**
     * Push current viewport into a stack
     */
    saveViewport: function () {
        this._viewportStack.push(this.viewport);
    },

    /**
     * Pop viewport from stack, restore in the renderer
     */
    restoreViewport: function () {
        if (this._viewportStack.length > 0) {
            this.setViewport(this._viewportStack.pop());
        }
    },

    /**
     * Push current clear into a stack
     */
    saveClear: function () {
        this._clearStack.push({
            clearBit: this.clearBit,
            clearColor: this.clearColor
        });
    },

    /**
     * Pop clear from stack, restore in the renderer
     */
    restoreClear: function () {
        if (this._clearStack.length > 0) {
            var opt = this._clearStack.pop();
            this.clearColor = opt.clearColor;
            this.clearBit = opt.clearBit;
        }
    },

    bindSceneRendering: function (scene) {
        this._sceneRendering = scene;
    },

    /**
     * Render the scene in camera to the screen or binded offline framebuffer
     * @param  {clay.Scene}       scene
     * @param  {clay.Camera}      camera
     * @param  {boolean}     [notUpdateScene] If not call the scene.update methods in the rendering, default true
     * @param  {boolean}     [preZ]           If use preZ optimization, default false
     * @return {IRenderInfo}
     */
    render: function(scene, camera, notUpdateScene, preZ) {
        var _gl = this.gl;

        var clearColor = this.clearColor;

        if (this.clearBit) {

            // Must set depth and color mask true before clear
            _gl.colorMask(true, true, true, true);
            _gl.depthMask(true);
            var viewport = this.viewport;
            var needsScissor = false;
            var viewportDpr = viewport.devicePixelRatio;
            if (viewport.width !== this._width || viewport.height !== this._height
                || (viewportDpr && viewportDpr !== this.devicePixelRatio)
                || viewport.x || viewport.y
            ) {
                needsScissor = true;
                // http://stackoverflow.com/questions/11544608/how-to-clear-a-rectangle-area-in-webgl
                // Only clear the viewport
                _gl.enable(_gl.SCISSOR_TEST);
                _gl.scissor(viewport.x * viewportDpr, viewport.y * viewportDpr, viewport.width * viewportDpr, viewport.height * viewportDpr);
            }
            _gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
            _gl.clear(this.clearBit);
            if (needsScissor) {
                _gl.disable(_gl.SCISSOR_TEST);
            }
        }

        // If the scene have been updated in the prepass like shadow map
        // There is no need to update it again
        if (!notUpdateScene) {
            scene.update(false);
        }
        scene.updateLights();

        camera = camera || scene.getMainCamera();
        if (!camera) {
            console.error('Can\'t find camera in the scene.');
            return;
        }
        camera.update();
        var renderList = scene.updateRenderList(camera, true);

        this._sceneRendering = scene;

        var opaqueList = renderList.opaque;
        var transparentList = renderList.transparent;
        var sceneMaterial = scene.material;

        scene.trigger('beforerender', this, scene, camera, renderList);

        // Render pre z
        if (preZ) {
            this.renderPreZ(opaqueList, scene, camera);
            _gl.depthFunc(_gl.LEQUAL);
        }
        else {
            _gl.depthFunc(_gl.LESS);
        }

        // Update the depth of transparent list.
        var worldViewMat = mat4Create();
        var posViewSpace = glmatrix_vec3.create();
        for (var i = 0; i < transparentList.length; i++) {
            var renderable = transparentList[i];
            glmatrix_mat4.multiplyAffine(worldViewMat, camera.viewMatrix.array, renderable.worldTransform.array);
            glmatrix_vec3.transformMat4(posViewSpace, renderable.position.array, worldViewMat);
            renderable.__depth = posViewSpace[2];
        }

        // Render opaque list
        this.renderPass(opaqueList, camera, {
            getMaterial: function (renderable) {
                return sceneMaterial || renderable.material;
            },
            sortCompare: this.opaqueSortCompare
        });

        this.renderPass(transparentList, camera, {
            getMaterial: function (renderable) {
                return sceneMaterial || renderable.material;
            },
            sortCompare: this.transparentSortCompare
        });

        scene.trigger('afterrender', this, scene, camera, renderList);

        // Cleanup
        this._sceneRendering = null;
    },

    getProgram: function (renderable, renderMaterial, scene) {
        renderMaterial = renderMaterial || renderable.material;
        return this._programMgr.getProgram(renderable, renderMaterial, scene);
    },

    validateProgram: function (program) {
        if (program.__error) {
            var errorMsg = program.__error;
            if (errorShader[program.__uid__]) {
                return;
            }
            errorShader[program.__uid__] = true;

            if (this.throwError) {
                throw new Error(errorMsg);
            }
            else {
                this.trigger('error', errorMsg);
            }

        }

    },

    updatePrograms: function (list, scene, passConfig) {
        var getMaterial = (passConfig && passConfig.getMaterial) || defaultGetMaterial;
        scene = scene || null;
        for (var i = 0; i < list.length; i++) {
            var renderable = list[i];
            var renderMaterial = getMaterial.call(this, renderable);
            if (i > 0) {
                var prevRenderable = list[i - 1];
                var prevJointsLen = prevRenderable.joints ? prevRenderable.joints.length : 0;
                var jointsLen = renderable.joints ? renderable.joints.length : 0;
                // Keep program not change if joints, material, lightGroup are same of two renderables.
                if (jointsLen === prevJointsLen
                    && renderable.material === prevRenderable.material
                    && renderable.lightGroup === prevRenderable.lightGroup
                ) {
                    renderable.__program = prevRenderable.__program;
                    continue;
                }
            }

            var program = this._programMgr.getProgram(renderable, renderMaterial, scene);

            this.validateProgram(program);

            renderable.__program = program;
        }
    },

    /**
     * Render a single renderable list in camera in sequence
     * @param {clay.Renderable[]} list List of all renderables.
     * @param {clay.Camera} [camera] Camera provide view matrix and porjection matrix. It can be null.
     * @param {Object} [passConfig]
     * @param {Function} [passConfig.getMaterial] Get renderable material.
     * @param {Function} [passConfig.getUniform] Get material uniform value.
     * @param {Function} [passConfig.isMaterialChanged] If material changed.
     * @param {Function} [passConfig.beforeRender] Before render each renderable.
     * @param {Function} [passConfig.afterRender] After render each renderable
     * @param {Function} [passConfig.ifRender] If render the renderable.
     * @param {Function} [passConfig.sortCompare] Sort compare function.
     * @return {IRenderInfo}
     */
    renderPass: function(list, camera, passConfig) {
        this.trigger('beforerenderpass', this, list, camera, passConfig);

        passConfig = passConfig || {};
        passConfig.getMaterial = passConfig.getMaterial || defaultGetMaterial;
        passConfig.getUniform = passConfig.getUniform || defaultGetUniform;
        // PENDING Better solution?
        passConfig.isMaterialChanged = passConfig.isMaterialChanged || defaultIsMaterialChanged;
        passConfig.beforeRender = passConfig.beforeRender || noop;
        passConfig.afterRender = passConfig.afterRender || noop;

        var ifRenderObject = passConfig.ifRender || defaultIfRender;

        this.updatePrograms(list, this._sceneRendering, passConfig);
        if (passConfig.sortCompare) {
            list.sort(passConfig.sortCompare);
        }

        // Some common builtin uniforms
        var viewport = this.viewport;
        var vDpr = viewport.devicePixelRatio;
        var viewportUniform = [
            viewport.x * vDpr, viewport.y * vDpr,
            viewport.width * vDpr, viewport.height * vDpr
        ];
        var windowDpr = this.devicePixelRatio;
        var windowSizeUniform = this.__currentFrameBuffer
            ? [this.__currentFrameBuffer.getTextureWidth(), this.__currentFrameBuffer.getTextureHeight()]
            : [this._width * windowDpr, this._height * windowDpr];
        // DEPRECATED
        var viewportSizeUniform = [
            viewportUniform[2], viewportUniform[3]
        ];
        var time = Date.now();

        // Calculate view and projection matrix
        if (camera) {
            glmatrix_mat4.copy(matrices.VIEW, camera.viewMatrix.array);
            glmatrix_mat4.copy(matrices.PROJECTION, camera.projectionMatrix.array);
            glmatrix_mat4.copy(matrices.VIEWINVERSE, camera.worldTransform.array);
        }
        else {
            glmatrix_mat4.identity(matrices.VIEW);
            glmatrix_mat4.identity(matrices.PROJECTION);
            glmatrix_mat4.identity(matrices.VIEWINVERSE);
        }
        glmatrix_mat4.multiply(matrices.VIEWPROJECTION, matrices.PROJECTION, matrices.VIEW);
        glmatrix_mat4.invert(matrices.PROJECTIONINVERSE, matrices.PROJECTION);
        glmatrix_mat4.invert(matrices.VIEWPROJECTIONINVERSE, matrices.VIEWPROJECTION);

        var _gl = this.gl;
        var scene = this._sceneRendering;

        var prevMaterial;
        var prevProgram;
        var prevRenderable;

        // Status
        var depthTest, depthMask;
        var culling, cullFace, frontFace;
        var transparent;
        var drawID;
        var currentVAO;
        var materialTakesTextureSlot;

        // var vaoExt = this.getGLExtension('OES_vertex_array_object');
        // not use vaoExt, some platforms may mess it up.
        var vaoExt = null;

        for (var i = 0; i < list.length; i++) {
            var renderable = list[i];
            var isSceneNode = renderable.worldTransform != null;
            var worldM;

            if (!ifRenderObject(renderable)) {
                continue;
            }

            // Skinned mesh will transformed to joint space. Ignore the mesh transform
            if (isSceneNode) {
                worldM = (renderable.isSkinnedMesh && renderable.isSkinnedMesh())
                    // TODO
                    ? (renderable.offsetMatrix ? renderable.offsetMatrix.array :matrices.IDENTITY)
                    : renderable.worldTransform.array;
            }
            var geometry = renderable.geometry;
            var material = passConfig.getMaterial.call(this, renderable);

            var program = renderable.__program;
            var shader = material.shader;

            var currentDrawID = geometry.__uid__ + '-' + program.__uid__;
            var drawIDChanged = currentDrawID !== drawID;
            drawID = currentDrawID;
            if (drawIDChanged && vaoExt) {
                // TODO Seems need to be bound to null immediately (or before bind another program?) if vao is changed
                vaoExt.bindVertexArrayOES(null);
            }
            if (isSceneNode) {
                glmatrix_mat4.copy(matrices.WORLD, worldM);
                glmatrix_mat4.multiply(matrices.WORLDVIEWPROJECTION, matrices.VIEWPROJECTION, worldM);
                glmatrix_mat4.multiplyAffine(matrices.WORLDVIEW, matrices.VIEW, worldM);
                if (shader.matrixSemantics.WORLDINVERSE ||
                    shader.matrixSemantics.WORLDINVERSETRANSPOSE) {
                    glmatrix_mat4.invert(matrices.WORLDINVERSE, worldM);
                }
                if (shader.matrixSemantics.WORLDVIEWINVERSE ||
                    shader.matrixSemantics.WORLDVIEWINVERSETRANSPOSE) {
                    glmatrix_mat4.invert(matrices.WORLDVIEWINVERSE, matrices.WORLDVIEW);
                }
                if (shader.matrixSemantics.WORLDVIEWPROJECTIONINVERSE ||
                    shader.matrixSemantics.WORLDVIEWPROJECTIONINVERSETRANSPOSE) {
                    glmatrix_mat4.invert(matrices.WORLDVIEWPROJECTIONINVERSE, matrices.WORLDVIEWPROJECTION);
                }
            }

            // Before render hook
            renderable.beforeRender && renderable.beforeRender(this);
            passConfig.beforeRender.call(this, renderable, material, prevMaterial);

            var programChanged = program !== prevProgram;
            if (programChanged) {
                // Set lights number
                program.bind(this);
                // Set some common uniforms
                program.setUniformOfSemantic(_gl, 'VIEWPORT', viewportUniform);
                program.setUniformOfSemantic(_gl, 'WINDOW_SIZE', windowSizeUniform);
                if (camera) {
                    program.setUniformOfSemantic(_gl, 'NEAR', camera.near);
                    program.setUniformOfSemantic(_gl, 'FAR', camera.far);
                }
                program.setUniformOfSemantic(_gl, 'DEVICEPIXELRATIO', vDpr);
                program.setUniformOfSemantic(_gl, 'TIME', time);
                // DEPRECATED
                program.setUniformOfSemantic(_gl, 'VIEWPORT_SIZE', viewportSizeUniform);

                // Set lights uniforms
                // TODO needs optimized
                if (scene) {
                    scene.setLightUniforms(program, renderable.lightGroup, this);
                }
            }
            else {
                program = prevProgram;
            }

            // Program changes also needs reset the materials.
            if (programChanged || passConfig.isMaterialChanged(
                renderable, prevRenderable, material, prevMaterial
            )) {
                if (material.depthTest !== depthTest) {
                    material.depthTest ? _gl.enable(_gl.DEPTH_TEST) : _gl.disable(_gl.DEPTH_TEST);
                    depthTest = material.depthTest;
                }
                if (material.depthMask !== depthMask) {
                    _gl.depthMask(material.depthMask);
                    depthMask = material.depthMask;
                }
                if (material.transparent !== transparent) {
                    material.transparent ? _gl.enable(_gl.BLEND) : _gl.disable(_gl.BLEND);
                    transparent = material.transparent;
                }
                // TODO cache blending
                if (material.transparent) {
                    if (material.blend) {
                        material.blend(_gl);
                    }
                    else {
                        // Default blend function
                        _gl.blendEquationSeparate(_gl.FUNC_ADD, _gl.FUNC_ADD);
                        _gl.blendFuncSeparate(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA);
                    }
                }

                materialTakesTextureSlot = this._bindMaterial(
                    renderable, material, program,
                    prevRenderable || null, prevMaterial || null, prevProgram || null,
                    passConfig.getUniform
                );
                prevMaterial = material;
            }

            var matrixSemanticKeys = shader.matrixSemanticKeys;

            if (isSceneNode) {
                for (var k = 0; k < matrixSemanticKeys.length; k++) {
                    var semantic = matrixSemanticKeys[k];
                    var semanticInfo = shader.matrixSemantics[semantic];
                    var matrix = matrices[semantic];
                    if (semanticInfo.isTranspose) {
                        var matrixNoTranspose = matrices[semanticInfo.semanticNoTranspose];
                        glmatrix_mat4.transpose(matrix, matrixNoTranspose);
                    }
                    program.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, matrix);
                }
            }

            if (renderable.cullFace !== cullFace) {
                cullFace = renderable.cullFace;
                _gl.cullFace(cullFace);
            }
            if (renderable.frontFace !== frontFace) {
                frontFace = renderable.frontFace;
                _gl.frontFace(frontFace);
            }
            if (renderable.culling !== culling) {
                culling = renderable.culling;
                culling ? _gl.enable(_gl.CULL_FACE) : _gl.disable(_gl.CULL_FACE);
            }
            // TODO Not update skeleton in each renderable.
            this._updateSkeleton(renderable, program, materialTakesTextureSlot);
            if (drawIDChanged) {
                currentVAO = this._bindVAO(vaoExt, shader, geometry, program);
            }
            this._renderObject(renderable, currentVAO, program);

            // After render hook
            passConfig.afterRender(this, renderable);
            renderable.afterRender && renderable.afterRender(this);

            prevProgram = program;
            prevRenderable = renderable;
        }

        // TODO Seems need to be bound to null immediately if vao is changed?
        if (vaoExt) {
            vaoExt.bindVertexArrayOES(null);
        }

        this.trigger('afterrenderpass', this, list, camera, passConfig);
    },

    getMaxJointNumber: function () {
        return this.maxJointNumber;
    },

    _updateSkeleton: function (object, program, slot) {
        var _gl = this.gl;
        var skeleton = object.skeleton;
        // Set pose matrices of skinned mesh
        if (skeleton) {
            // TODO Update before culling.
            skeleton.update();
            if (object.joints.length > this.getMaxJointNumber()) {
                var skinMatricesTexture = skeleton.getSubSkinMatricesTexture(object.__uid__, object.joints);
                program.useTextureSlot(this, skinMatricesTexture, slot);
                program.setUniform(_gl, '1i', 'skinMatricesTexture', slot);
                program.setUniform(_gl, '1f', 'skinMatricesTextureSize', skinMatricesTexture.width);
            }
            else {
                var skinMatricesArray = skeleton.getSubSkinMatrices(object.__uid__, object.joints);
                program.setUniformOfSemantic(_gl, 'SKIN_MATRIX', skinMatricesArray);
            }
        }
    },

    _renderObject: function (renderable, vao, program) {
        var _gl = this.gl;
        var geometry = renderable.geometry;

        var glDrawMode = renderable.mode;
        if (glDrawMode == null) {
            glDrawMode = 0x0004;
        }

        var ext = null;
        var isInstanced = renderable.isInstancedMesh && renderable.isInstancedMesh();
        if (isInstanced) {
            ext = this.getGLExtension('ANGLE_instanced_arrays');
            if (!ext) {
                console.warn('Device not support ANGLE_instanced_arrays extension');
                return;
            }
        }

        var instancedAttrLocations;
        if (isInstanced) {
            instancedAttrLocations = this._bindInstancedAttributes(renderable, program, ext);
        }

        if (vao.indicesBuffer) {
            var uintExt = this.getGLExtension('OES_element_index_uint');
            var useUintExt = uintExt && (geometry.indices instanceof Uint32Array);
            var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT;

            if (isInstanced) {
                ext.drawElementsInstancedANGLE(
                    glDrawMode, vao.indicesBuffer.count, indicesType, 0, renderable.getInstanceCount()
                );
            }
            else {
                _gl.drawElements(glDrawMode, vao.indicesBuffer.count, indicesType, 0);
            }
        }
        else {
            if (isInstanced) {
                ext.drawArraysInstancedANGLE(glDrawMode, 0, geometry.vertexCount, renderable.getInstanceCount());
            }
            else {
                // FIXME Use vertex number in buffer
                // vertexCount may get the wrong value when geometry forget to mark dirty after update
                _gl.drawArrays(glDrawMode, 0, geometry.vertexCount);
            }
        }

        if (isInstanced) {
            for (var i = 0; i < instancedAttrLocations.length; i++) {
                _gl.disableVertexAttribArray(instancedAttrLocations[i]);
            }
        }
    },

    _bindInstancedAttributes: function (renderable, program, ext) {
        var _gl = this.gl;
        var instancedBuffers = renderable.getInstancedAttributesBuffers(this);
        var locations = [];

        for (var i = 0; i < instancedBuffers.length; i++) {
            var bufferObj = instancedBuffers[i];
            var location = program.getAttribLocation(_gl, bufferObj.symbol);
            if (location < 0) {
                continue;
            }

            var glType = attributeBufferTypeMap[bufferObj.type] || _gl.FLOAT;;
            _gl.enableVertexAttribArray(location);  // TODO
            _gl.bindBuffer(_gl.ARRAY_BUFFER, bufferObj.buffer);
            _gl.vertexAttribPointer(location, bufferObj.size, glType, false, 0, 0);
            ext.vertexAttribDivisorANGLE(location, bufferObj.divisor);

            locations.push(location);
        }

        return locations;
    },

    _bindMaterial: function (renderable, material, program, prevRenderable, prevMaterial, prevProgram, getUniformValue) {
        var _gl = this.gl;
        // PENDING Same texture in different material take different slot?

        // May use shader of other material if shader code are same
        var sameProgram = prevProgram === program;

        var currentTextureSlot = program.currentTextureSlot();
        var enabledUniforms = material.getEnabledUniforms();
        var textureUniforms = material.getTextureUniforms();
        var placeholderTexture = this._placeholderTexture;

        for (var u = 0; u < textureUniforms.length; u++) {
            var symbol = textureUniforms[u];
            var uniformValue = getUniformValue(renderable, material, symbol);
            var uniformType = material.uniforms[symbol].type;
            // Not use `instanceof` to determine if a value is texture in Material#bind.
            // Use type instead, in some case texture may be in different namespaces.
            // TODO Duck type validate.
            if (uniformType === 't' && uniformValue) {
                // Reset slot
                uniformValue.__slot = -1;
            }
            else if (uniformType === 'tv') {
                for (var i = 0; i < uniformValue.length; i++) {
                    if (uniformValue[i]) {
                        uniformValue[i].__slot = -1;
                    }
                }
            }
        }

        placeholderTexture.__slot = -1;

        // Set uniforms
        for (var u = 0; u < enabledUniforms.length; u++) {
            var symbol = enabledUniforms[u];
            var uniform = material.uniforms[symbol];
            var uniformValue = getUniformValue(renderable, material, symbol);
            var uniformType = uniform.type;
            var isTexture = uniformType === 't';

            if (isTexture) {
                if (!uniformValue || !uniformValue.isRenderable()) {
                    uniformValue = placeholderTexture;
                }
            }
            // PENDING
            // When binding two materials with the same shader
            // Many uniforms will be be set twice even if they have the same value
            // So add a evaluation to see if the uniform is really needed to be set
            if (prevMaterial && sameProgram) {
                var prevUniformValue = getUniformValue(prevRenderable, prevMaterial, symbol);
                if (isTexture) {
                    if (!prevUniformValue || !prevUniformValue.isRenderable()) {
                        prevUniformValue = placeholderTexture;
                    }
                }

                if (prevUniformValue === uniformValue) {
                    if (isTexture) {
                        // Still take the slot to make sure same texture in different materials have same slot.
                        program.takeCurrentTextureSlot(this, null);
                    }
                    else if (uniformType === 'tv' && uniformValue) {
                        for (var i = 0; i < uniformValue.length; i++) {
                            program.takeCurrentTextureSlot(this, null);
                        }
                    }
                    continue;
                }
            }

            if (uniformValue == null) {
                continue;
            }
            else if (isTexture) {
                if (uniformValue.__slot < 0) {
                    var slot = program.currentTextureSlot();
                    var res = program.setUniform(_gl, '1i', symbol, slot);
                    if (res) { // Texture uniform is enabled
                        program.takeCurrentTextureSlot(this, uniformValue);
                        uniformValue.__slot = slot;
                    }
                }
                // Multiple uniform use same texture..
                else {
                    program.setUniform(_gl, '1i', symbol, uniformValue.__slot);
                }
            }
            else if (Array.isArray(uniformValue)) {
                if (uniformValue.length === 0) {
                    continue;
                }
                // Texture Array
                if (uniformType === 'tv') {
                    if (!program.hasUniform(symbol)) {
                        continue;
                    }

                    var arr = [];
                    for (var i = 0; i < uniformValue.length; i++) {
                        var texture = uniformValue[i];

                        if (texture.__slot < 0) {
                            var slot = program.currentTextureSlot();
                            arr.push(slot);
                            program.takeCurrentTextureSlot(this, texture);
                            texture.__slot = slot;
                        }
                        else {
                            arr.push(texture.__slot);
                        }
                    }

                    program.setUniform(_gl, '1iv', symbol, arr);
                }
                else {
                    program.setUniform(_gl, uniform.type, symbol, uniformValue);
                }
            }
            else{
                program.setUniform(_gl, uniform.type, symbol, uniformValue);
            }
        }
        var newSlot = program.currentTextureSlot();
        // Texture slot maybe used out of material.
        program.resetTextureSlot(currentTextureSlot);
        return newSlot;
    },

    _bindVAO: function (vaoExt, shader, geometry, program) {
        var isStatic = !geometry.dynamic;
        var _gl = this.gl;

        var vaoId = this.__uid__ + '-' + program.__uid__;
        var vao = geometry.__vaoCache[vaoId];
        if (!vao) {
            var chunks = geometry.getBufferChunks(this);
            if (!chunks || !chunks.length) {  // Empty mesh
                return;
            }
            var chunk = chunks[0];
            var attributeBuffers = chunk.attributeBuffers;
            var indicesBuffer = chunk.indicesBuffer;

            var availableAttributes = [];
            var availableAttributeSymbols = [];
            for (var a = 0; a < attributeBuffers.length; a++) {
                var attributeBufferInfo = attributeBuffers[a];
                var name = attributeBufferInfo.name;
                var semantic = attributeBufferInfo.semantic;
                var symbol;
                if (semantic) {
                    var semanticInfo = shader.attributeSemantics[semantic];
                    symbol = semanticInfo && semanticInfo.symbol;
                }
                else {
                    symbol = name;
                }
                if (symbol && program.attributes[symbol]) {
                    availableAttributes.push(attributeBufferInfo);
                    availableAttributeSymbols.push(symbol);
                }
            }

            vao = new VertexArrayObject(
                availableAttributes,
                availableAttributeSymbols,
                indicesBuffer
            );

            if (isStatic) {
                geometry.__vaoCache[vaoId] = vao;
            }
        }

        var needsBindAttributes = true;

        // Create vertex object array cost a lot
        // So we don't use it on the dynamic object
        if (vaoExt && isStatic) {
            // Use vertex array object
            // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html
            if (vao.vao == null) {
                vao.vao = vaoExt.createVertexArrayOES();
            }
            else {
                needsBindAttributes = false;
            }
            vaoExt.bindVertexArrayOES(vao.vao);
        }

        var availableAttributes = vao.availableAttributes;
        var indicesBuffer = vao.indicesBuffer;

        if (needsBindAttributes) {
            var locationList = program.enableAttributes(this, vao.availableAttributeSymbols, (vaoExt && isStatic && vao));
            // Setting attributes;
            for (var a = 0; a < availableAttributes.length; a++) {
                var location = locationList[a];
                if (location === -1) {
                    continue;
                }
                var attributeBufferInfo = availableAttributes[a];
                var buffer = attributeBufferInfo.buffer;
                var size = attributeBufferInfo.size;
                var glType = attributeBufferTypeMap[attributeBufferInfo.type] || _gl.FLOAT;

                _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
                _gl.vertexAttribPointer(location, size, glType, false, 0, 0);
            }

            if (geometry.isUseIndices()) {
                _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer);
            }
        }

        return vao;
    },

    renderPreZ: function (list, scene, camera) {
        var _gl = this.gl;
        var preZPassMaterial = this._prezMaterial || new src_Material({
            shader: new src_Shader(src_Shader.source('clay.prez.vertex'), src_Shader.source('clay.prez.fragment'))
        });
        this._prezMaterial = preZPassMaterial;

        _gl.colorMask(false, false, false, false);
        _gl.depthMask(true);

        // Status
        this.renderPass(list, camera, {
            ifRender: function (renderable) {
                return !renderable.ignorePreZ;
            },
            isMaterialChanged: function (renderable, prevRenderable) {
                var matA = renderable.material;
                var matB = prevRenderable.material;
                return matA.get('diffuseMap') !== matB.get('diffuseMap')
                    || (matA.get('alphaCutoff') || 0) !== (matB.get('alphaCutoff') || 0);
            },
            getUniform: function (renderable, depthMaterial, symbol) {
                if (symbol === 'alphaMap') {
                    return renderable.material.get('diffuseMap');
                }
                else if (symbol === 'alphaCutoff') {
                    if (renderable.material.isDefined('fragment', 'ALPHA_TEST')
                        && renderable.material.get('diffuseMap')
                    ) {
                        var alphaCutoff = renderable.material.get('alphaCutoff');
                        return alphaCutoff || 0;
                    }
                    return 0;
                }
                else if (symbol === 'uvRepeat') {
                    return renderable.material.get('uvRepeat');
                }
                else if (symbol === 'uvOffset') {
                    return renderable.material.get('uvOffset');
                }
                else {
                    return depthMaterial.get(symbol);
                }
            },
            getMaterial: function () {
                return preZPassMaterial;
            },
            sort: this.opaqueSortCompare
        });

        _gl.colorMask(true, true, true, true);
        _gl.depthMask(true);
    },

    /**
     * Dispose given scene, including all geometris, textures and shaders in the scene
     * @param {clay.Scene} scene
     */
    disposeScene: function(scene) {
        this.disposeNode(scene, true, true);
        scene.dispose();
    },

    /**
     * Dispose given node, including all geometries, textures and shaders attached on it or its descendant
     * @param {clay.Node} node
     * @param {boolean} [disposeGeometry=false] If dispose the geometries used in the descendant mesh
     * @param {boolean} [disposeTexture=false] If dispose the textures used in the descendant mesh
     */
    disposeNode: function(root, disposeGeometry, disposeTexture) {
        // Dettached from parent
        if (root.getParent()) {
            root.getParent().remove(root);
        }
        var disposedMap = {};
        root.traverse(function(node) {
            var material = node.material;
            if (node.geometry && disposeGeometry) {
                node.geometry.dispose(this);
            }
            if (disposeTexture && material && !disposedMap[material.__uid__]) {
                var textureUniforms = material.getTextureUniforms();
                for (var u = 0; u < textureUniforms.length; u++) {
                    var uniformName = textureUniforms[u];
                    var val = material.uniforms[uniformName].value;
                    var uniformType = material.uniforms[uniformName].type;
                    if (!val) {
                        continue;
                    }
                    if (uniformType === 't') {
                        val.dispose && val.dispose(this);
                    }
                    else if (uniformType === 'tv') {
                        for (var k = 0; k < val.length; k++) {
                            if (val[k]) {
                                val[k].dispose && val[k].dispose(this);
                            }
                        }
                    }
                }
                disposedMap[material.__uid__] = true;
            }
            // Particle system and AmbientCubemap light need to dispose
            if (node.dispose) {
                node.dispose(this);
            }
        }, this);
    },

    /**
     * Dispose given geometry
     * @param {clay.Geometry} geometry
     */
    disposeGeometry: function(geometry) {
        geometry.dispose(this);
    },

    /**
     * Dispose given texture
     * @param {clay.Texture} texture
     */
    disposeTexture: function(texture) {
        texture.dispose(this);
    },

    /**
     * Dispose given frame buffer
     * @param {clay.FrameBuffer} frameBuffer
     */
    disposeFrameBuffer: function(frameBuffer) {
        frameBuffer.dispose(this);
    },

    /**
     * Dispose renderer
     */
    dispose: function () {},

    /**
     * Convert screen coords to normalized device coordinates(NDC)
     * Screen coords can get from mouse event, it is positioned relative to canvas element
     * NDC can be used in ray casting with Camera.prototype.castRay methods
     *
     * @param  {number}       x
     * @param  {number}       y
     * @param  {clay.Vector2} [out]
     * @return {clay.Vector2}
     */
    screenToNDC: function(x, y, out) {
        if (!out) {
            out = new math_Vector2();
        }
        // Invert y;
        y = this._height - y;

        var viewport = this.viewport;
        var arr = out.array;
        arr[0] = (x - viewport.x) / viewport.width;
        arr[0] = arr[0] * 2 - 1;
        arr[1] = (y - viewport.y) / viewport.height;
        arr[1] = arr[1] * 2 - 1;

        return out;
    }
});

/**
 * Opaque renderables compare function
 * @param  {clay.Renderable} x
 * @param  {clay.Renderable} y
 * @return {boolean}
 * @static
 */
Renderer.opaqueSortCompare = Renderer.prototype.opaqueSortCompare = function(x, y) {
    // Priority renderOrder -> program -> material -> geometry
    if (x.renderOrder === y.renderOrder) {
        if (x.__program === y.__program) {
            if (x.material === y.material) {
                return x.geometry.__uid__ - y.geometry.__uid__;
            }
            return x.material.__uid__ - y.material.__uid__;
        }
        if (x.__program && y.__program) {
            return x.__program.__uid__ - y.__program.__uid__;
        }
        return 0;
    }
    return x.renderOrder - y.renderOrder;
};

/**
 * Transparent renderables compare function
 * @param  {clay.Renderable} a
 * @param  {clay.Renderable} b
 * @return {boolean}
 * @static
 */
Renderer.transparentSortCompare = Renderer.prototype.transparentSortCompare = function(x, y) {
    // Priority renderOrder -> depth -> program -> material -> geometry

    if (x.renderOrder === y.renderOrder) {
        if (x.__depth === y.__depth) {
            if (x.__program === y.__program) {
                if (x.material === y.material) {
                    return x.geometry.__uid__ - y.geometry.__uid__;
                }
                return x.material.__uid__ - y.material.__uid__;
            }
            if (x.__program  && y.__program) {
                return x.__program.__uid__ - y.__program.__uid__;
            }
            return 0;
        }
        // Depth is negative
        // So farther object has smaller depth value
        return x.__depth - y.__depth;
    }
    return x.renderOrder - y.renderOrder;
};

// Temporary variables
var matrices = {
    IDENTITY: mat4Create(),

    WORLD: mat4Create(),
    VIEW: mat4Create(),
    PROJECTION: mat4Create(),
    WORLDVIEW: mat4Create(),
    VIEWPROJECTION: mat4Create(),
    WORLDVIEWPROJECTION: mat4Create(),

    WORLDINVERSE: mat4Create(),
    VIEWINVERSE: mat4Create(),
    PROJECTIONINVERSE: mat4Create(),
    WORLDVIEWINVERSE: mat4Create(),
    VIEWPROJECTIONINVERSE: mat4Create(),
    WORLDVIEWPROJECTIONINVERSE: mat4Create(),

    WORLDTRANSPOSE: mat4Create(),
    VIEWTRANSPOSE: mat4Create(),
    PROJECTIONTRANSPOSE: mat4Create(),
    WORLDVIEWTRANSPOSE: mat4Create(),
    VIEWPROJECTIONTRANSPOSE: mat4Create(),
    WORLDVIEWPROJECTIONTRANSPOSE: mat4Create(),
    WORLDINVERSETRANSPOSE: mat4Create(),
    VIEWINVERSETRANSPOSE: mat4Create(),
    PROJECTIONINVERSETRANSPOSE: mat4Create(),
    WORLDVIEWINVERSETRANSPOSE: mat4Create(),
    VIEWPROJECTIONINVERSETRANSPOSE: mat4Create(),
    WORLDVIEWPROJECTIONINVERSETRANSPOSE: mat4Create()
};

/**
 * @name clay.Renderer.COLOR_BUFFER_BIT
 * @type {number}
 */
Renderer.COLOR_BUFFER_BIT = glenum.COLOR_BUFFER_BIT;
/**
 * @name clay.Renderer.DEPTH_BUFFER_BIT
 * @type {number}
 */
Renderer.DEPTH_BUFFER_BIT = glenum.DEPTH_BUFFER_BIT;
/**
 * @name clay.Renderer.STENCIL_BUFFER_BIT
 * @type {number}
 */
Renderer.STENCIL_BUFFER_BIT = glenum.STENCIL_BUFFER_BIT;

/* harmony default export */ const src_Renderer = (Renderer);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Vector3.js


/**
 * @constructor
 * @alias clay.Vector3
 * @param {number} x
 * @param {number} y
 * @param {number} z
 */
var Vector3 = function(x, y, z) {

    x = x || 0;
    y = y || 0;
    z = z || 0;

    /**
     * Storage of Vector3, read and write of x, y, z will change the values in array
     * All methods also operate on the array instead of x, y, z components
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Vector3#
     */
    this.array = glmatrix_vec3.fromValues(x, y, z);

    /**
     * Dirty flag is used by the Node to determine
     * if the matrix is updated to latest
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Vector3#
     */
    this._dirty = true;
};

Vector3.prototype = {

    constructor: Vector3,

    /**
     * Add b to self
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    add: function (b) {
        glmatrix_vec3.add(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y and z components
     * @param  {number}  x
     * @param  {number}  y
     * @param  {number}  z
     * @return {clay.Vector3}
     */
    set: function (x, y, z) {
        this.array[0] = x;
        this.array[1] = y;
        this.array[2] = z;
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y and z components from array
     * @param  {Float32Array|number[]} arr
     * @return {clay.Vector3}
     */
    setArray: function (arr) {
        this.array[0] = arr[0];
        this.array[1] = arr[1];
        this.array[2] = arr[2];

        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Vector3
     * @return {clay.Vector3}
     */
    clone: function () {
        return new Vector3(this.x, this.y, this.z);
    },

    /**
     * Copy from b
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    copy: function (b) {
        glmatrix_vec3.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Cross product of self and b, written to a Vector3 out
     * @param  {clay.Vector3} a
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    cross: function (a, b) {
        glmatrix_vec3.cross(this.array, a.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for distance
     * @param  {clay.Vector3} b
     * @return {number}
     */
    dist: function (b) {
        return glmatrix_vec3.dist(this.array, b.array);
    },

    /**
     * Distance between self and b
     * @param  {clay.Vector3} b
     * @return {number}
     */
    distance: function (b) {
        return glmatrix_vec3.distance(this.array, b.array);
    },

    /**
     * Alias for divide
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    div: function (b) {
        glmatrix_vec3.div(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Divide self by b
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    divide: function (b) {
        glmatrix_vec3.divide(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Dot product of self and b
     * @param  {clay.Vector3} b
     * @return {number}
     */
    dot: function (b) {
        return glmatrix_vec3.dot(this.array, b.array);
    },

    /**
     * Alias of length
     * @return {number}
     */
    len: function () {
        return glmatrix_vec3.len(this.array);
    },

    /**
     * Calculate the length
     * @return {number}
     */
    length: function () {
        return glmatrix_vec3.length(this.array);
    },
    /**
     * Linear interpolation between a and b
     * @param  {clay.Vector3} a
     * @param  {clay.Vector3} b
     * @param  {number}  t
     * @return {clay.Vector3}
     */
    lerp: function (a, b, t) {
        glmatrix_vec3.lerp(this.array, a.array, b.array, t);
        this._dirty = true;
        return this;
    },

    /**
     * Minimum of self and b
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    min: function (b) {
        glmatrix_vec3.min(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Maximum of self and b
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    max: function (b) {
        glmatrix_vec3.max(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiply
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    mul: function (b) {
        glmatrix_vec3.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Mutiply self and b
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    multiply: function (b) {
        glmatrix_vec3.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Negate self
     * @return {clay.Vector3}
     */
    negate: function () {
        glmatrix_vec3.negate(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Normalize self
     * @return {clay.Vector3}
     */
    normalize: function () {
        glmatrix_vec3.normalize(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Generate random x, y, z components with a given scale
     * @param  {number} scale
     * @return {clay.Vector3}
     */
    random: function (scale) {
        glmatrix_vec3.random(this.array, scale);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self
     * @param  {number}  scale
     * @return {clay.Vector3}
     */
    scale: function (s) {
        glmatrix_vec3.scale(this.array, this.array, s);
        this._dirty = true;
        return this;
    },

    /**
     * Scale b and add to self
     * @param  {clay.Vector3} b
     * @param  {number}  scale
     * @return {clay.Vector3}
     */
    scaleAndAdd: function (b, s) {
        glmatrix_vec3.scaleAndAdd(this.array, this.array, b.array, s);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for squaredDistance
     * @param  {clay.Vector3} b
     * @return {number}
     */
    sqrDist: function (b) {
        return glmatrix_vec3.sqrDist(this.array, b.array);
    },

    /**
     * Squared distance between self and b
     * @param  {clay.Vector3} b
     * @return {number}
     */
    squaredDistance: function (b) {
        return glmatrix_vec3.squaredDistance(this.array, b.array);
    },

    /**
     * Alias for squaredLength
     * @return {number}
     */
    sqrLen: function () {
        return glmatrix_vec3.sqrLen(this.array);
    },

    /**
     * Squared length of self
     * @return {number}
     */
    squaredLength: function () {
        return glmatrix_vec3.squaredLength(this.array);
    },

    /**
     * Alias for subtract
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    sub: function (b) {
        glmatrix_vec3.sub(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Subtract b from self
     * @param  {clay.Vector3} b
     * @return {clay.Vector3}
     */
    subtract: function (b) {
        glmatrix_vec3.subtract(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix3 m
     * @param  {clay.Matrix3} m
     * @return {clay.Vector3}
     */
    transformMat3: function (m) {
        glmatrix_vec3.transformMat3(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix4 m
     * @param  {clay.Matrix4} m
     * @return {clay.Vector3}
     */
    transformMat4: function (m) {
        glmatrix_vec3.transformMat4(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },
    /**
     * Transform self with a Quaternion q
     * @param  {clay.Quaternion} q
     * @return {clay.Vector3}
     */
    transformQuat: function (q) {
        glmatrix_vec3.transformQuat(this.array, this.array, q.array);
        this._dirty = true;
        return this;
    },

    /**
     * Trasnform self into projection space with m
     * @param  {clay.Matrix4} m
     * @return {clay.Vector3}
     */
    applyProjection: function (m) {
        var v = this.array;
        m = m.array;

        // Perspective projection
        if (m[15] === 0) {
            var w = -1 / v[2];
            v[0] = m[0] * v[0] * w;
            v[1] = m[5] * v[1] * w;
            v[2] = (m[10] * v[2] + m[14]) * w;
        }
        else {
            v[0] = m[0] * v[0] + m[12];
            v[1] = m[5] * v[1] + m[13];
            v[2] = m[10] * v[2] + m[14];
        }
        this._dirty = true;

        return this;
    },

    eulerFromQuat: function(q, order) {
        Vector3.eulerFromQuat(this, q, order);
    },

    eulerFromMat3: function (m, order) {
        Vector3.eulerFromMat3(this, m, order);
    },

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

var defineProperty = Object.defineProperty;
// Getter and Setter
if (defineProperty) {

    var Vector3_proto = Vector3.prototype;
    /**
     * @name x
     * @type {number}
     * @memberOf clay.Vector3
     * @instance
     */
    defineProperty(Vector3_proto, 'x', {
        get: function () {
            return this.array[0];
        },
        set: function (value) {
            this.array[0] = value;
            this._dirty = true;
        }
    });

    /**
     * @name y
     * @type {number}
     * @memberOf clay.Vector3
     * @instance
     */
    defineProperty(Vector3_proto, 'y', {
        get: function () {
            return this.array[1];
        },
        set: function (value) {
            this.array[1] = value;
            this._dirty = true;
        }
    });

    /**
     * @name z
     * @type {number}
     * @memberOf clay.Vector3
     * @instance
     */
    defineProperty(Vector3_proto, 'z', {
        get: function () {
            return this.array[2];
        },
        set: function (value) {
            this.array[2] = value;
            this._dirty = true;
        }
    });
}


// Supply methods that are not in place

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.add = function(out, a, b) {
    glmatrix_vec3.add(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} out
 * @param  {number}  x
 * @param  {number}  y
 * @param  {number}  z
 * @return {clay.Vector3}
 */
Vector3.set = function(out, x, y, z) {
    glmatrix_vec3.set(out.array, x, y, z);
    out._dirty = true;
};

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.copy = function(out, b) {
    glmatrix_vec3.copy(out.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.cross = function(out, a, b) {
    glmatrix_vec3.cross(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {number}
 */
Vector3.dist = function(a, b) {
    return glmatrix_vec3.distance(a.array, b.array);
};

/**
 * @function
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {number}
 */
Vector3.distance = Vector3.dist;

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.div = function(out, a, b) {
    glmatrix_vec3.divide(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.divide = Vector3.div;

/**
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {number}
 */
Vector3.dot = function(a, b) {
    return glmatrix_vec3.dot(a.array, b.array);
};

/**
 * @param  {clay.Vector3} a
 * @return {number}
 */
Vector3.len = function(b) {
    return glmatrix_vec3.length(b.array);
};

// Vector3.length = Vector3.len;

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @param  {number}  t
 * @return {clay.Vector3}
 */
Vector3.lerp = function(out, a, b, t) {
    glmatrix_vec3.lerp(out.array, a.array, b.array, t);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.min = function(out, a, b) {
    glmatrix_vec3.min(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.max = function(out, a, b) {
    glmatrix_vec3.max(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.mul = function(out, a, b) {
    glmatrix_vec3.multiply(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.multiply = Vector3.mul;
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @return {clay.Vector3}
 */
Vector3.negate = function(out, a) {
    glmatrix_vec3.negate(out.array, a.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @return {clay.Vector3}
 */
Vector3.normalize = function(out, a) {
    glmatrix_vec3.normalize(out.array, a.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {number}  scale
 * @return {clay.Vector3}
 */
Vector3.random = function(out, scale) {
    glmatrix_vec3.random(out.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {number}  scale
 * @return {clay.Vector3}
 */
Vector3.scale = function(out, a, scale) {
    glmatrix_vec3.scale(out.array, a.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @param  {number}  scale
 * @return {clay.Vector3}
 */
Vector3.scaleAndAdd = function(out, a, b, scale) {
    glmatrix_vec3.scaleAndAdd(out.array, a.array, b.array, scale);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {number}
 */
Vector3.sqrDist = function(a, b) {
    return glmatrix_vec3.sqrDist(a.array, b.array);
};
/**
 * @function
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {number}
 */
Vector3.squaredDistance = Vector3.sqrDist;
/**
 * @param  {clay.Vector3} a
 * @return {number}
 */
Vector3.sqrLen = function(a) {
    return glmatrix_vec3.sqrLen(a.array);
};
/**
 * @function
 * @param  {clay.Vector3} a
 * @return {number}
 */
Vector3.squaredLength = Vector3.sqrLen;

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.sub = function(out, a, b) {
    glmatrix_vec3.subtract(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Vector3} b
 * @return {clay.Vector3}
 */
Vector3.subtract = Vector3.sub;

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {Matrix3} m
 * @return {clay.Vector3}
 */
Vector3.transformMat3 = function(out, a, m) {
    glmatrix_vec3.transformMat3(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Matrix4} m
 * @return {clay.Vector3}
 */
Vector3.transformMat4 = function(out, a, m) {
    glmatrix_vec3.transformMat4(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {clay.Vector3} out
 * @param  {clay.Vector3} a
 * @param  {clay.Quaternion} q
 * @return {clay.Vector3}
 */
Vector3.transformQuat = function(out, a, q) {
    glmatrix_vec3.transformQuat(out.array, a.array, q.array);
    out._dirty = true;
    return out;
};

function clamp(val, min, max) {
    return val < min ? min : (val > max ? max : val);
}
var atan2 = Math.atan2;
var asin = Math.asin;
var abs = Math.abs;
/**
 * Convert quaternion to euler angle
 * Quaternion must be normalized
 * From three.js
 */
Vector3.eulerFromQuat = function (out, q, order) {
    out._dirty = true;
    q = q.array;

    var target = out.array;
    var x = q[0], y = q[1], z = q[2], w = q[3];
    var x2 = x * x;
    var y2 = y * y;
    var z2 = z * z;
    var w2 = w * w;

    var order = (order || 'XYZ').toUpperCase();

    switch (order) {
        case 'XYZ':
            target[0] = atan2(2 * (x * w - y * z), (w2 - x2 - y2 + z2));
            target[1] = asin(clamp(2 * (x * z + y * w), - 1, 1));
            target[2] = atan2(2 * (z * w - x * y), (w2 + x2 - y2 - z2));
            break;
        case 'YXZ':
            target[0] = asin(clamp(2 * (x * w - y * z), - 1, 1));
            target[1] = atan2(2 * (x * z + y * w), (w2 - x2 - y2 + z2));
            target[2] = atan2(2 * (x * y + z * w), (w2 - x2 + y2 - z2));
            break;
        case 'ZXY':
            target[0] = asin(clamp(2 * (x * w + y * z), - 1, 1));
            target[1] = atan2(2 * (y * w - z * x), (w2 - x2 - y2 + z2));
            target[2] = atan2(2 * (z * w - x * y), (w2 - x2 + y2 - z2));
            break;
        case 'ZYX':
            target[0] = atan2(2 * (x * w + z * y), (w2 - x2 - y2 + z2));
            target[1] = asin(clamp(2 * (y * w - x * z), - 1, 1));
            target[2] = atan2(2 * (x * y + z * w), (w2 + x2 - y2 - z2));
            break;
        case 'YZX':
            target[0] = atan2(2 * (x * w - z * y), (w2 - x2 + y2 - z2));
            target[1] = atan2(2 * (y * w - x * z), (w2 + x2 - y2 - z2));
            target[2] = asin(clamp(2 * (x * y + z * w), - 1, 1));
            break;
        case 'XZY':
            target[0] = atan2(2 * (x * w + y * z), (w2 - x2 + y2 - z2));
            target[1] = atan2(2 * (x * z + y * w), (w2 + x2 - y2 - z2));
            target[2] = asin(clamp(2 * (z * w - x * y), - 1, 1));
            break;
        default:
            console.warn('Unkown order: ' + order);
    }
    return out;
};

/**
 * Convert rotation matrix to euler angle
 * from three.js
 */
Vector3.eulerFromMat3 = function (out, m, order) {
    // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
    var te = m.array;
    var m11 = te[0], m12 = te[3], m13 = te[6];
    var m21 = te[1], m22 = te[4], m23 = te[7];
    var m31 = te[2], m32 = te[5], m33 = te[8];
    var target = out.array;

    var order = (order || 'XYZ').toUpperCase();

    switch (order) {
        case 'XYZ':
            target[1] = asin(clamp(m13, -1, 1));
            if (abs(m13) < 0.99999) {
                target[0] = atan2(-m23, m33);
                target[2] = atan2(-m12, m11);
            }
            else {
                target[0] = atan2(m32, m22);
                target[2] = 0;
            }
            break;
        case 'YXZ':
            target[0] = asin(-clamp(m23, -1, 1));
            if (abs(m23) < 0.99999) {
                target[1] = atan2(m13, m33);
                target[2] = atan2(m21, m22);
            }
            else {
                target[1] = atan2(-m31, m11);
                target[2] = 0;
            }
            break;
        case 'ZXY':
            target[0] = asin(clamp(m32, -1, 1));
            if (abs(m32) < 0.99999) {
                target[1] = atan2(-m31, m33);
                target[2] = atan2(-m12, m22);
            }
            else {
                target[1] = 0;
                target[2] = atan2(m21, m11);
            }
            break;
        case 'ZYX':
            target[1] = asin(-clamp(m31, -1, 1));
            if (abs(m31) < 0.99999) {
                target[0] = atan2(m32, m33);
                target[2] = atan2(m21, m11);
            }
            else {
                target[0] = 0;
                target[2] = atan2(-m12, m22);
            }
            break;
        case 'YZX':
            target[2] = asin(clamp(m21, -1, 1));
            if (abs(m21) < 0.99999) {
                target[0] = atan2(-m23, m22);
                target[1] = atan2(-m31, m11);
            }
            else {
                target[0] = 0;
                target[1] = atan2(m13, m33);
            }
            break;
        case 'XZY':
            target[2] = asin(-clamp(m12, -1, 1));
            if (abs(m12) < 0.99999) {
                target[0] = atan2(m32, m22);
                target[1] = atan2(m13, m11);
            }
            else {
                target[0] = atan2(-m23, m33);
                target[1] = 0;
            }
            break;
        default:
            console.warn('Unkown order: ' + order);
    }
    out._dirty = true;

    return out;
};

Object.defineProperties(Vector3, {
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    POSITIVE_X: {
        get: function () {
            return new Vector3(1, 0, 0);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    NEGATIVE_X: {
        get: function () {
            return new Vector3(-1, 0, 0);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    POSITIVE_Y: {
        get: function () {
            return new Vector3(0, 1, 0);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    NEGATIVE_Y: {
        get: function () {
            return new Vector3(0, -1, 0);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    POSITIVE_Z: {
        get: function () {
            return new Vector3(0, 0, 1);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     */
    NEGATIVE_Z: {
        get: function () {
            return new Vector3(0, 0, -1);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    UP: {
        get: function () {
            return new Vector3(0, 1, 0);
        }
    },
    /**
     * @type {clay.Vector3}
     * @readOnly
     * @memberOf clay.Vector3
     */
    ZERO: {
        get: function () {
            return new Vector3();
        }
    }
});

/* harmony default export */ const math_Vector3 = (Vector3);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Ray.js



var EPSILON = 1e-5;

/**
 * @constructor
 * @alias clay.Ray
 * @param {clay.Vector3} [origin]
 * @param {clay.Vector3} [direction]
 */
var Ray = function (origin, direction) {
    /**
     * @type {clay.Vector3}
     */
    this.origin = origin || new math_Vector3();
    /**
     * @type {clay.Vector3}
     */
    this.direction = direction || new math_Vector3();
};

Ray.prototype = {

    constructor: Ray,

    // http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm
    /**
     * Calculate intersection point between ray and a give plane
     * @param  {clay.Plane} plane
     * @param  {clay.Vector3} [out]
     * @return {clay.Vector3}
     */
    intersectPlane: function (plane, out) {
        var pn = plane.normal.array;
        var d = plane.distance;
        var ro = this.origin.array;
        var rd = this.direction.array;

        var divider = glmatrix_vec3.dot(pn, rd);
        // ray is parallel to the plane
        if (divider === 0) {
            return null;
        }
        if (!out) {
            out = new math_Vector3();
        }
        var t = (glmatrix_vec3.dot(pn, ro) - d) / divider;
        glmatrix_vec3.scaleAndAdd(out.array, ro, rd, -t);
        out._dirty = true;
        return out;
    },

    /**
     * Mirror the ray against plane
     * @param  {clay.Plane} plane
     */
    mirrorAgainstPlane: function (plane) {
        // Distance to plane
        var d = glmatrix_vec3.dot(plane.normal.array, this.direction.array);
        glmatrix_vec3.scaleAndAdd(this.direction.array, this.direction.array, plane.normal.array, -d * 2);
        this.direction._dirty = true;
    },

    distanceToPoint: (function () {
        var v = glmatrix_vec3.create();
        return function (point) {
            glmatrix_vec3.sub(v, point, this.origin.array);
            // Distance from projection point to origin
            var b = glmatrix_vec3.dot(v, this.direction.array);
            if (b < 0) {
                return glmatrix_vec3.distance(this.origin.array, point);
            }
            // Squared distance from center to origin
            var c2 = glmatrix_vec3.lenSquared(v);
            // Squared distance from center to projection point
            return Math.sqrt(c2 - b * b);
        };
    })(),

    /**
     * Calculate intersection point between ray and sphere
     * @param  {clay.Vector3} center
     * @param  {number} radius
     * @param  {clay.Vector3} out
     * @return {clay.Vector3}
     */
    intersectSphere: (function () {
        var v = glmatrix_vec3.create();
        return function (center, radius, out) {
            var origin = this.origin.array;
            var direction = this.direction.array;
            center = center.array;
            glmatrix_vec3.sub(v, center, origin);
            // Distance from projection point to origin
            var b = glmatrix_vec3.dot(v, direction);
            // Squared distance from center to origin
            var c2 = glmatrix_vec3.squaredLength(v);
            // Squared distance from center to projection point
            var d2 = c2 - b * b;

            var r2 = radius * radius;
            // No intersection
            if (d2 > r2) {
                return;
            }

            var a = Math.sqrt(r2 - d2);
            // First intersect point
            var t0 = b - a;
            // Second intersect point
            var t1 = b + a;

            if (!out) {
                out = new math_Vector3();
            }
            if (t0 < 0) {
                if (t1 < 0) {
                    return null;
                }
                else {
                    glmatrix_vec3.scaleAndAdd(out.array, origin, direction, t1);
                    return out;
                }
            }
            else {
                glmatrix_vec3.scaleAndAdd(out.array, origin, direction, t0);
                return out;
            }
        };
    })(),

    // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/
    /**
     * Calculate intersection point between ray and bounding box
     * @param {clay.BoundingBox} bbox
     * @param {clay.Vector3}
     * @return {clay.Vector3}
     */
    intersectBoundingBox: function (bbox, out) {
        var dir = this.direction.array;
        var origin = this.origin.array;
        var min = bbox.min.array;
        var max = bbox.max.array;

        var invdirx = 1 / dir[0];
        var invdiry = 1 / dir[1];
        var invdirz = 1 / dir[2];

        var tmin, tmax, tymin, tymax, tzmin, tzmax;
        if (invdirx >= 0) {
            tmin = (min[0] - origin[0]) * invdirx;
            tmax = (max[0] - origin[0]) * invdirx;
        }
        else {
            tmax = (min[0] - origin[0]) * invdirx;
            tmin = (max[0] - origin[0]) * invdirx;
        }
        if (invdiry >= 0) {
            tymin = (min[1] - origin[1]) * invdiry;
            tymax = (max[1] - origin[1]) * invdiry;
        }
        else {
            tymax = (min[1] - origin[1]) * invdiry;
            tymin = (max[1] - origin[1]) * invdiry;
        }

        if ((tmin > tymax) || (tymin > tmax)) {
            return null;
        }

        if (tymin > tmin || tmin !== tmin) {
            tmin = tymin;
        }
        if (tymax < tmax || tmax !== tmax) {
            tmax = tymax;
        }

        if (invdirz >= 0) {
            tzmin = (min[2] - origin[2]) * invdirz;
            tzmax = (max[2] - origin[2]) * invdirz;
        }
        else {
            tzmax = (min[2] - origin[2]) * invdirz;
            tzmin = (max[2] - origin[2]) * invdirz;
        }

        if ((tmin > tzmax) || (tzmin > tmax)) {
            return null;
        }

        if (tzmin > tmin || tmin !== tmin) {
            tmin = tzmin;
        }
        if (tzmax < tmax || tmax !== tmax) {
            tmax = tzmax;
        }
        if (tmax < 0) {
            return null;
        }

        var t = tmin >= 0 ? tmin : tmax;

        if (!out) {
            out = new math_Vector3();
        }
        glmatrix_vec3.scaleAndAdd(out.array, origin, dir, t);
        return out;
    },

    // http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
    /**
     * Calculate intersection point between ray and three triangle vertices
     * @param {clay.Vector3} a
     * @param {clay.Vector3} b
     * @param {clay.Vector3} c
     * @param {boolean}           singleSided, CW triangle will be ignored
     * @param {clay.Vector3} [out]
     * @param {clay.Vector3} [barycenteric] barycentric coords
     * @return {clay.Vector3}
     */
    intersectTriangle: (function () {

        var eBA = glmatrix_vec3.create();
        var eCA = glmatrix_vec3.create();
        var AO = glmatrix_vec3.create();
        var vCross = glmatrix_vec3.create();

        return function (a, b, c, singleSided, out, barycenteric) {
            var dir = this.direction.array;
            var origin = this.origin.array;
            a = a.array;
            b = b.array;
            c = c.array;

            glmatrix_vec3.sub(eBA, b, a);
            glmatrix_vec3.sub(eCA, c, a);

            glmatrix_vec3.cross(vCross, eCA, dir);

            var det = glmatrix_vec3.dot(eBA, vCross);

            if (singleSided) {
                if (det > -EPSILON) {
                    return null;
                }
            }
            else {
                if (det > -EPSILON && det < EPSILON) {
                    return null;
                }
            }

            glmatrix_vec3.sub(AO, origin, a);
            var u = glmatrix_vec3.dot(vCross, AO) / det;
            if (u < 0 || u > 1) {
                return null;
            }

            glmatrix_vec3.cross(vCross, eBA, AO);
            var v = glmatrix_vec3.dot(dir, vCross) / det;

            if (v < 0 || v > 1 || (u + v > 1)) {
                return null;
            }

            glmatrix_vec3.cross(vCross, eBA, eCA);
            var t = -glmatrix_vec3.dot(AO, vCross) / det;

            if (t < 0) {
                return null;
            }

            if (!out) {
                out = new math_Vector3();
            }
            if (barycenteric) {
                math_Vector3.set(barycenteric, (1 - u - v), u, v);
            }
            glmatrix_vec3.scaleAndAdd(out.array, origin, dir, t);

            return out;
        };
    })(),

    /**
     * Apply an affine transform matrix to the ray
     * @return {clay.Matrix4} matrix
     */
    applyTransform: function (matrix) {
        math_Vector3.add(this.direction, this.direction, this.origin);
        math_Vector3.transformMat4(this.origin, this.origin, matrix);
        math_Vector3.transformMat4(this.direction, this.direction, matrix);

        math_Vector3.sub(this.direction, this.direction, this.origin);
        math_Vector3.normalize(this.direction, this.direction);
    },

    /**
     * Copy values from another ray
     * @param {clay.Ray} ray
     */
    copy: function (ray) {
        math_Vector3.copy(this.origin, ray.origin);
        math_Vector3.copy(this.direction, ray.direction);
    },

    /**
     * Clone a new ray
     * @return {clay.Ray}
     */
    clone: function () {
        var ray = new Ray();
        ray.copy(this);
        return ray;
    }
};

/* harmony default export */ const math_Ray = (Ray);

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/vec4.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 4 Dimensional Vector
 * @name vec4
 */

var vec4 = {};

/**
 * Creates a new, empty vec4
 *
 * @returns {vec4} a new 4D vector
 */
vec4.create = function() {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    return out;
};

/**
 * Creates a new vec4 initialized with values from an existing vector
 *
 * @param {vec4} a vector to clone
 * @returns {vec4} a new 4D vector
 */
vec4.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Creates a new vec4 initialized with the given values
 *
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @param {Number} w W component
 * @returns {vec4} a new 4D vector
 */
vec4.fromValues = function(x, y, z, w) {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = x;
    out[1] = y;
    out[2] = z;
    out[3] = w;
    return out;
};

/**
 * Copy the values from one vec4 to another
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the source vector
 * @returns {vec4} out
 */
vec4.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Set the components of a vec4 to the given values
 *
 * @param {vec4} out the receiving vector
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @param {Number} w W component
 * @returns {vec4} out
 */
vec4.set = function(out, x, y, z, w) {
    out[0] = x;
    out[1] = y;
    out[2] = z;
    out[3] = w;
    return out;
};

/**
 * Adds two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.add = function(out, a, b) {
    out[0] = a[0] + b[0];
    out[1] = a[1] + b[1];
    out[2] = a[2] + b[2];
    out[3] = a[3] + b[3];
    return out;
};

/**
 * Subtracts vector b from vector a
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.subtract = function(out, a, b) {
    out[0] = a[0] - b[0];
    out[1] = a[1] - b[1];
    out[2] = a[2] - b[2];
    out[3] = a[3] - b[3];
    return out;
};

/**
 * Alias for {@link vec4.subtract}
 * @function
 */
vec4.sub = vec4.subtract;

/**
 * Multiplies two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.multiply = function(out, a, b) {
    out[0] = a[0] * b[0];
    out[1] = a[1] * b[1];
    out[2] = a[2] * b[2];
    out[3] = a[3] * b[3];
    return out;
};

/**
 * Alias for {@link vec4.multiply}
 * @function
 */
vec4.mul = vec4.multiply;

/**
 * Divides two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.divide = function(out, a, b) {
    out[0] = a[0] / b[0];
    out[1] = a[1] / b[1];
    out[2] = a[2] / b[2];
    out[3] = a[3] / b[3];
    return out;
};

/**
 * Alias for {@link vec4.divide}
 * @function
 */
vec4.div = vec4.divide;

/**
 * Returns the minimum of two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.min = function(out, a, b) {
    out[0] = Math.min(a[0], b[0]);
    out[1] = Math.min(a[1], b[1]);
    out[2] = Math.min(a[2], b[2]);
    out[3] = Math.min(a[3], b[3]);
    return out;
};

/**
 * Returns the maximum of two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {vec4} out
 */
vec4.max = function(out, a, b) {
    out[0] = Math.max(a[0], b[0]);
    out[1] = Math.max(a[1], b[1]);
    out[2] = Math.max(a[2], b[2]);
    out[3] = Math.max(a[3], b[3]);
    return out;
};

/**
 * Scales a vec4 by a scalar number
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the vector to scale
 * @param {Number} b amount to scale the vector by
 * @returns {vec4} out
 */
vec4.scale = function(out, a, b) {
    out[0] = a[0] * b;
    out[1] = a[1] * b;
    out[2] = a[2] * b;
    out[3] = a[3] * b;
    return out;
};

/**
 * Adds two vec4's after scaling the second operand by a scalar value
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @param {Number} scale the amount to scale b by before adding
 * @returns {vec4} out
 */
vec4.scaleAndAdd = function(out, a, b, scale) {
    out[0] = a[0] + (b[0] * scale);
    out[1] = a[1] + (b[1] * scale);
    out[2] = a[2] + (b[2] * scale);
    out[3] = a[3] + (b[3] * scale);
    return out;
};

/**
 * Calculates the euclidian distance between two vec4's
 *
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {Number} distance between a and b
 */
vec4.distance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1],
        z = b[2] - a[2],
        w = b[3] - a[3];
    return Math.sqrt(x*x + y*y + z*z + w*w);
};

/**
 * Alias for {@link vec4.distance}
 * @function
 */
vec4.dist = vec4.distance;

/**
 * Calculates the squared euclidian distance between two vec4's
 *
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {Number} squared distance between a and b
 */
vec4.squaredDistance = function(a, b) {
    var x = b[0] - a[0],
        y = b[1] - a[1],
        z = b[2] - a[2],
        w = b[3] - a[3];
    return x*x + y*y + z*z + w*w;
};

/**
 * Alias for {@link vec4.squaredDistance}
 * @function
 */
vec4.sqrDist = vec4.squaredDistance;

/**
 * Calculates the length of a vec4
 *
 * @param {vec4} a vector to calculate length of
 * @returns {Number} length of a
 */
vec4.length = function (a) {
    var x = a[0],
        y = a[1],
        z = a[2],
        w = a[3];
    return Math.sqrt(x*x + y*y + z*z + w*w);
};

/**
 * Alias for {@link vec4.length}
 * @function
 */
vec4.len = vec4.length;

/**
 * Calculates the squared length of a vec4
 *
 * @param {vec4} a vector to calculate squared length of
 * @returns {Number} squared length of a
 */
vec4.squaredLength = function (a) {
    var x = a[0],
        y = a[1],
        z = a[2],
        w = a[3];
    return x*x + y*y + z*z + w*w;
};

/**
 * Alias for {@link vec4.squaredLength}
 * @function
 */
vec4.sqrLen = vec4.squaredLength;

/**
 * Negates the components of a vec4
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a vector to negate
 * @returns {vec4} out
 */
vec4.negate = function(out, a) {
    out[0] = -a[0];
    out[1] = -a[1];
    out[2] = -a[2];
    out[3] = -a[3];
    return out;
};

/**
 * Returns the inverse of the components of a vec4
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a vector to invert
 * @returns {vec4} out
 */
vec4.inverse = function(out, a) {
  out[0] = 1.0 / a[0];
  out[1] = 1.0 / a[1];
  out[2] = 1.0 / a[2];
  out[3] = 1.0 / a[3];
  return out;
};

/**
 * Normalize a vec4
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a vector to normalize
 * @returns {vec4} out
 */
vec4.normalize = function(out, a) {
    var x = a[0],
        y = a[1],
        z = a[2],
        w = a[3];
    var len = x*x + y*y + z*z + w*w;
    if (len > 0) {
        len = 1 / Math.sqrt(len);
        out[0] = a[0] * len;
        out[1] = a[1] * len;
        out[2] = a[2] * len;
        out[3] = a[3] * len;
    }
    return out;
};

/**
 * Calculates the dot product of two vec4's
 *
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @returns {Number} dot product of a and b
 */
vec4.dot = function (a, b) {
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
};

/**
 * Performs a linear interpolation between two vec4's
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the first operand
 * @param {vec4} b the second operand
 * @param {Number} t interpolation amount between the two inputs
 * @returns {vec4} out
 */
vec4.lerp = function (out, a, b, t) {
    var ax = a[0],
        ay = a[1],
        az = a[2],
        aw = a[3];
    out[0] = ax + t * (b[0] - ax);
    out[1] = ay + t * (b[1] - ay);
    out[2] = az + t * (b[2] - az);
    out[3] = aw + t * (b[3] - aw);
    return out;
};

/**
 * Generates a random vector with the given scale
 *
 * @param {vec4} out the receiving vector
 * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
 * @returns {vec4} out
 */
vec4.random = function (out, scale) {
    scale = scale || 1.0;

    //TODO: This is a pretty awful way of doing this. Find something better.
    out[0] = common_GLMAT_RANDOM();
    out[1] = common_GLMAT_RANDOM();
    out[2] = common_GLMAT_RANDOM();
    out[3] = common_GLMAT_RANDOM();
    vec4.normalize(out, out);
    vec4.scale(out, out, scale);
    return out;
};

/**
 * Transforms the vec4 with a mat4.
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the vector to transform
 * @param {mat4} m matrix to transform with
 * @returns {vec4} out
 */
vec4.transformMat4 = function(out, a, m) {
    var x = a[0], y = a[1], z = a[2], w = a[3];
    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;
    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
    return out;
};

/**
 * Transforms the vec4 with a quat
 *
 * @param {vec4} out the receiving vector
 * @param {vec4} a the vector to transform
 * @param {quat} q quaternion to transform with
 * @returns {vec4} out
 */
vec4.transformQuat = function(out, a, q) {
    var x = a[0], y = a[1], z = a[2],
        qx = q[0], qy = q[1], qz = q[2], qw = q[3],

        // calculate quat * vec
        ix = qw * x + qy * z - qz * y,
        iy = qw * y + qz * x - qx * z,
        iz = qw * z + qx * y - qy * x,
        iw = -qx * x - qy * y - qz * z;

    // calculate result * inverse quat
    out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
    out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
    out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
    return out;
};

/**
 * Perform some operation over an array of vec4s.
 *
 * @param {Array} a the array of vectors to iterate over
 * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
 * @param {Number} offset Number of elements to skip at the beginning of the array
 * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array
 * @param {Function} fn Function to call for each vector in the array
 * @param {Object} [arg] additional argument to pass to fn
 * @returns {Array} a
 * @function
 */
vec4.forEach = (function() {
    var vec = vec4.create();

    return function(a, stride, offset, count, fn, arg) {
        var i, l;
        if(!stride) {
            stride = 4;
        }

        if(!offset) {
            offset = 0;
        }

        if(count) {
            l = Math.min((count * stride) + offset, a.length);
        } else {
            l = a.length;
        }

        for(i = offset; i < l; i += stride) {
            vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
            fn(vec, vec, arg);
            a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
        }

        return a;
    };
})();

/* harmony default export */ const glmatrix_vec4 = (vec4);
;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat3.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 3x3 Matrix
 * @name mat3
 */

var mat3 = {};

/**
 * Creates a new identity mat3
 *
 * @returns {mat3} a new 3x3 matrix
 */
mat3.create = function() {
    var out = new GLMAT_ARRAY_TYPE(9);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 1;
    out[5] = 0;
    out[6] = 0;
    out[7] = 0;
    out[8] = 1;
    return out;
};

/**
 * Copies the upper-left 3x3 values into the given mat3.
 *
 * @param {mat3} out the receiving 3x3 matrix
 * @param {mat4} a   the source 4x4 matrix
 * @returns {mat3} out
 */
mat3.fromMat4 = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[4];
    out[4] = a[5];
    out[5] = a[6];
    out[6] = a[8];
    out[7] = a[9];
    out[8] = a[10];
    return out;
};

/**
 * Creates a new mat3 initialized with values from an existing matrix
 *
 * @param {mat3} a matrix to clone
 * @returns {mat3} a new 3x3 matrix
 */
mat3.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(9);
    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];
    return out;
};

/**
 * Copy the values from one mat3 to another
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the source matrix
 * @returns {mat3} out
 */
mat3.copy = function(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];
    return out;
};

/**
 * Set a mat3 to the identity matrix
 *
 * @param {mat3} out the receiving matrix
 * @returns {mat3} out
 */
mat3.identity = function(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 0;
    out[4] = 1;
    out[5] = 0;
    out[6] = 0;
    out[7] = 0;
    out[8] = 1;
    return out;
};

/**
 * Transpose the values of a mat3
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the source matrix
 * @returns {mat3} out
 */
mat3.transpose = function(out, a) {
    // If we are transposing ourselves we can skip a few steps but have to cache some values
    if (out === a) {
        var a01 = a[1], a02 = a[2], a12 = a[5];
        out[1] = a[3];
        out[2] = a[6];
        out[3] = a01;
        out[5] = a[7];
        out[6] = a02;
        out[7] = a12;
    } else {
        out[0] = a[0];
        out[1] = a[3];
        out[2] = a[6];
        out[3] = a[1];
        out[4] = a[4];
        out[5] = a[7];
        out[6] = a[2];
        out[7] = a[5];
        out[8] = a[8];
    }

    return out;
};

/**
 * Inverts a mat3
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the source matrix
 * @returns {mat3} out
 */
mat3.invert = function(out, a) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8],

        b01 = a22 * a11 - a12 * a21,
        b11 = -a22 * a10 + a12 * a20,
        b21 = a21 * a10 - a11 * a20,

        // Calculate the determinant
        det = a00 * b01 + a01 * b11 + a02 * b21;

    if (!det) {
        return null;
    }
    det = 1.0 / det;

    out[0] = b01 * det;
    out[1] = (-a22 * a01 + a02 * a21) * det;
    out[2] = (a12 * a01 - a02 * a11) * det;
    out[3] = b11 * det;
    out[4] = (a22 * a00 - a02 * a20) * det;
    out[5] = (-a12 * a00 + a02 * a10) * det;
    out[6] = b21 * det;
    out[7] = (-a21 * a00 + a01 * a20) * det;
    out[8] = (a11 * a00 - a01 * a10) * det;
    return out;
};

/**
 * Calculates the adjugate of a mat3
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the source matrix
 * @returns {mat3} out
 */
mat3.adjoint = function(out, a) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8];

    out[0] = (a11 * a22 - a12 * a21);
    out[1] = (a02 * a21 - a01 * a22);
    out[2] = (a01 * a12 - a02 * a11);
    out[3] = (a12 * a20 - a10 * a22);
    out[4] = (a00 * a22 - a02 * a20);
    out[5] = (a02 * a10 - a00 * a12);
    out[6] = (a10 * a21 - a11 * a20);
    out[7] = (a01 * a20 - a00 * a21);
    out[8] = (a00 * a11 - a01 * a10);
    return out;
};

/**
 * Calculates the determinant of a mat3
 *
 * @param {mat3} a the source matrix
 * @returns {Number} determinant of a
 */
mat3.determinant = function (a) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8];

    return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
};

/**
 * Multiplies two mat3's
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the first operand
 * @param {mat3} b the second operand
 * @returns {mat3} out
 */
mat3.multiply = function (out, a, b) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8],

        b00 = b[0], b01 = b[1], b02 = b[2],
        b10 = b[3], b11 = b[4], b12 = b[5],
        b20 = b[6], b21 = b[7], b22 = b[8];

    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
    out[2] = b00 * a02 + b01 * a12 + b02 * a22;

    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
    out[5] = b10 * a02 + b11 * a12 + b12 * a22;

    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
    return out;
};

/**
 * Alias for {@link mat3.multiply}
 * @function
 */
mat3.mul = mat3.multiply;

/**
 * Translate a mat3 by the given vector
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the matrix to translate
 * @param {vec2} v vector to translate by
 * @returns {mat3} out
 */
mat3.translate = function(out, a, v) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8],
        x = v[0], y = v[1];

    out[0] = a00;
    out[1] = a01;
    out[2] = a02;

    out[3] = a10;
    out[4] = a11;
    out[5] = a12;

    out[6] = x * a00 + y * a10 + a20;
    out[7] = x * a01 + y * a11 + a21;
    out[8] = x * a02 + y * a12 + a22;
    return out;
};

/**
 * Rotates a mat3 by the given angle
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat3} out
 */
mat3.rotate = function (out, a, rad) {
    var a00 = a[0], a01 = a[1], a02 = a[2],
        a10 = a[3], a11 = a[4], a12 = a[5],
        a20 = a[6], a21 = a[7], a22 = a[8],

        s = Math.sin(rad),
        c = Math.cos(rad);

    out[0] = c * a00 + s * a10;
    out[1] = c * a01 + s * a11;
    out[2] = c * a02 + s * a12;

    out[3] = c * a10 - s * a00;
    out[4] = c * a11 - s * a01;
    out[5] = c * a12 - s * a02;

    out[6] = a20;
    out[7] = a21;
    out[8] = a22;
    return out;
};

/**
 * Scales the mat3 by the dimensions in the given vec2
 *
 * @param {mat3} out the receiving matrix
 * @param {mat3} a the matrix to rotate
 * @param {vec2} v the vec2 to scale the matrix by
 * @returns {mat3} out
 **/
mat3.scale = function(out, a, v) {
    var x = v[0], y = v[1];

    out[0] = x * a[0];
    out[1] = x * a[1];
    out[2] = x * a[2];

    out[3] = y * a[3];
    out[4] = y * a[4];
    out[5] = y * a[5];

    out[6] = a[6];
    out[7] = a[7];
    out[8] = a[8];
    return out;
};

/**
 * Copies the values from a mat2d into a mat3
 *
 * @param {mat3} out the receiving matrix
 * @param {mat2d} a the matrix to copy
 * @returns {mat3} out
 **/
mat3.fromMat2d = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = 0;

    out[3] = a[2];
    out[4] = a[3];
    out[5] = 0;

    out[6] = a[4];
    out[7] = a[5];
    out[8] = 1;
    return out;
};

/**
* Calculates a 3x3 matrix from the given quaternion
*
* @param {mat3} out mat3 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat3} out
*/
mat3.fromQuat = function (out, q) {
    var x = q[0], y = q[1], z = q[2], w = q[3],
        x2 = x + x,
        y2 = y + y,
        z2 = z + z,

        xx = x * x2,
        yx = y * x2,
        yy = y * y2,
        zx = z * x2,
        zy = z * y2,
        zz = z * z2,
        wx = w * x2,
        wy = w * y2,
        wz = w * z2;

    out[0] = 1 - yy - zz;
    out[3] = yx - wz;
    out[6] = zx + wy;

    out[1] = yx + wz;
    out[4] = 1 - xx - zz;
    out[7] = zy - wx;

    out[2] = zx - wy;
    out[5] = zy + wx;
    out[8] = 1 - xx - yy;

    return out;
};

/**
* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
*
* @param {mat3} out mat3 receiving operation result
* @param {mat4} a Mat4 to derive the normal matrix from
*
* @returns {mat3} out
*/
mat3.normalFromMat4 = function (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,

        // Calculate the determinant
        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] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
    out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;

    out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
    out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
    out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;

    out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
    out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
    out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;

    return out;
};

/**
 * Returns Frobenius norm of a mat3
 *
 * @param {mat3} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat3.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)))
};


/* harmony default export */ const glmatrix_mat3 = (mat3);
;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/quat.js


/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */







/**
 * @class Quaternion
 * @name quat
 */

var quat = {};

/**
 * Creates a new identity quat
 *
 * @returns {quat} a new quaternion
 */
quat.create = function() {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Sets a quaternion to represent the shortest rotation from one
 * vector to another.
 *
 * Both vectors are assumed to be unit length.
 *
 * @param {quat} out the receiving quaternion.
 * @param {vec3} a the initial vector
 * @param {vec3} b the destination vector
 * @returns {quat} out
 */
quat.rotationTo = (function() {
    var tmpvec3 = glmatrix_vec3.create();
    var xUnitVec3 = glmatrix_vec3.fromValues(1,0,0);
    var yUnitVec3 = glmatrix_vec3.fromValues(0,1,0);

    return function(out, a, b) {
        var dot = glmatrix_vec3.dot(a, b);
        if (dot < -0.999999) {
            glmatrix_vec3.cross(tmpvec3, xUnitVec3, a);
            if (glmatrix_vec3.length(tmpvec3) < 0.000001)
                glmatrix_vec3.cross(tmpvec3, yUnitVec3, a);
            glmatrix_vec3.normalize(tmpvec3, tmpvec3);
            quat.setAxisAngle(out, tmpvec3, Math.PI);
            return out;
        } else if (dot > 0.999999) {
            out[0] = 0;
            out[1] = 0;
            out[2] = 0;
            out[3] = 1;
            return out;
        } else {
            glmatrix_vec3.cross(tmpvec3, a, b);
            out[0] = tmpvec3[0];
            out[1] = tmpvec3[1];
            out[2] = tmpvec3[2];
            out[3] = 1 + dot;
            return quat.normalize(out, out);
        }
    };
})();

/**
 * Sets the specified quaternion with values corresponding to the given
 * axes. Each axis is a vec3 and is expected to be unit length and
 * perpendicular to all other specified axes.
 *
 * @param {vec3} view  the vector representing the viewing direction
 * @param {vec3} right the vector representing the local "right" direction
 * @param {vec3} up    the vector representing the local "up" direction
 * @returns {quat} out
 */
quat.setAxes = (function() {
    var matr = glmatrix_mat3.create();

    return function(out, view, right, up) {
        matr[0] = right[0];
        matr[3] = right[1];
        matr[6] = right[2];

        matr[1] = up[0];
        matr[4] = up[1];
        matr[7] = up[2];

        matr[2] = -view[0];
        matr[5] = -view[1];
        matr[8] = -view[2];

        return quat.normalize(out, quat.fromMat3(out, matr));
    };
})();

/**
 * Creates a new quat initialized with values from an existing quaternion
 *
 * @param {quat} a quaternion to clone
 * @returns {quat} a new quaternion
 * @function
 */
quat.clone = glmatrix_vec4.clone;

/**
 * Creates a new quat initialized with the given values
 *
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @param {Number} w W component
 * @returns {quat} a new quaternion
 * @function
 */
quat.fromValues = glmatrix_vec4.fromValues;

/**
 * Copy the values from one quat to another
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a the source quaternion
 * @returns {quat} out
 * @function
 */
quat.copy = glmatrix_vec4.copy;

/**
 * Set the components of a quat to the given values
 *
 * @param {quat} out the receiving quaternion
 * @param {Number} x X component
 * @param {Number} y Y component
 * @param {Number} z Z component
 * @param {Number} w W component
 * @returns {quat} out
 * @function
 */
quat.set = glmatrix_vec4.set;

/**
 * Set a quat to the identity quaternion
 *
 * @param {quat} out the receiving quaternion
 * @returns {quat} out
 */
quat.identity = function(out) {
    out[0] = 0;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Sets a quat from the given angle and rotation axis,
 * then returns it.
 *
 * @param {quat} out the receiving quaternion
 * @param {vec3} axis the axis around which to rotate
 * @param {Number} rad the angle in radians
 * @returns {quat} out
 **/
quat.setAxisAngle = function(out, axis, rad) {
    rad = rad * 0.5;
    var s = Math.sin(rad);
    out[0] = s * axis[0];
    out[1] = s * axis[1];
    out[2] = s * axis[2];
    out[3] = Math.cos(rad);
    return out;
};

/**
 * Adds two quat's
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a the first operand
 * @param {quat} b the second operand
 * @returns {quat} out
 * @function
 */
quat.add = glmatrix_vec4.add;

/**
 * Multiplies two quat's
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a the first operand
 * @param {quat} b the second operand
 * @returns {quat} out
 */
quat.multiply = function(out, a, b) {
    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
        bx = b[0], by = b[1], bz = b[2], bw = b[3];

    out[0] = ax * bw + aw * bx + ay * bz - az * by;
    out[1] = ay * bw + aw * by + az * bx - ax * bz;
    out[2] = az * bw + aw * bz + ax * by - ay * bx;
    out[3] = aw * bw - ax * bx - ay * by - az * bz;
    return out;
};

/**
 * Alias for {@link quat.multiply}
 * @function
 */
quat.mul = quat.multiply;

/**
 * Scales a quat by a scalar number
 *
 * @param {quat} out the receiving vector
 * @param {quat} a the vector to scale
 * @param {Number} b amount to scale the vector by
 * @returns {quat} out
 * @function
 */
quat.scale = glmatrix_vec4.scale;

/**
 * Rotates a quaternion by the given angle about the X axis
 *
 * @param {quat} out quat receiving operation result
 * @param {quat} a quat to rotate
 * @param {number} rad angle (in radians) to rotate
 * @returns {quat} out
 */
quat.rotateX = function (out, a, rad) {
    rad *= 0.5;

    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
        bx = Math.sin(rad), bw = Math.cos(rad);

    out[0] = ax * bw + aw * bx;
    out[1] = ay * bw + az * bx;
    out[2] = az * bw - ay * bx;
    out[3] = aw * bw - ax * bx;
    return out;
};

/**
 * Rotates a quaternion by the given angle about the Y axis
 *
 * @param {quat} out quat receiving operation result
 * @param {quat} a quat to rotate
 * @param {number} rad angle (in radians) to rotate
 * @returns {quat} out
 */
quat.rotateY = function (out, a, rad) {
    rad *= 0.5;

    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
        by = Math.sin(rad), bw = Math.cos(rad);

    out[0] = ax * bw - az * by;
    out[1] = ay * bw + aw * by;
    out[2] = az * bw + ax * by;
    out[3] = aw * bw - ay * by;
    return out;
};

/**
 * Rotates a quaternion by the given angle about the Z axis
 *
 * @param {quat} out quat receiving operation result
 * @param {quat} a quat to rotate
 * @param {number} rad angle (in radians) to rotate
 * @returns {quat} out
 */
quat.rotateZ = function (out, a, rad) {
    rad *= 0.5;

    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
        bz = Math.sin(rad), bw = Math.cos(rad);

    out[0] = ax * bw + ay * bz;
    out[1] = ay * bw - ax * bz;
    out[2] = az * bw + aw * bz;
    out[3] = aw * bw - az * bz;
    return out;
};

/**
 * Calculates the W component of a quat from the X, Y, and Z components.
 * Assumes that quaternion is 1 unit in length.
 * Any existing W component will be ignored.
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a quat to calculate W component of
 * @returns {quat} out
 */
quat.calculateW = function (out, a) {
    var x = a[0], y = a[1], z = a[2];

    out[0] = x;
    out[1] = y;
    out[2] = z;
    out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
    return out;
};

/**
 * Calculates the dot product of two quat's
 *
 * @param {quat} a the first operand
 * @param {quat} b the second operand
 * @returns {Number} dot product of a and b
 * @function
 */
quat.dot = glmatrix_vec4.dot;

/**
 * Performs a linear interpolation between two quat's
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a the first operand
 * @param {quat} b the second operand
 * @param {Number} t interpolation amount between the two inputs
 * @returns {quat} out
 * @function
 */
quat.lerp = glmatrix_vec4.lerp;

/**
 * Performs a spherical linear interpolation between two quat
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a the first operand
 * @param {quat} b the second operand
 * @param {Number} t interpolation amount between the two inputs
 * @returns {quat} out
 */
quat.slerp = function (out, a, b, t) {
    // benchmarks:
    //    http://jsperf.com/quaternion-slerp-implementations

    var ax = a[0], ay = a[1], az = a[2], aw = a[3],
        bx = b[0], by = b[1], bz = b[2], bw = b[3];

    var        omega, cosom, sinom, scale0, scale1;

    // calc cosine
    cosom = ax * bx + ay * by + az * bz + aw * bw;
    // adjust signs (if necessary)
    if ( cosom < 0.0 ) {
        cosom = -cosom;
        bx = - bx;
        by = - by;
        bz = - bz;
        bw = - bw;
    }
    // calculate coefficients
    if ( (1.0 - cosom) > 0.000001 ) {
        // standard case (slerp)
        omega  = Math.acos(cosom);
        sinom  = Math.sin(omega);
        scale0 = Math.sin((1.0 - t) * omega) / sinom;
        scale1 = Math.sin(t * omega) / sinom;
    } else {
        // "from" and "to" quaternions are very close
        //  ... so we can do a linear interpolation
        scale0 = 1.0 - t;
        scale1 = t;
    }
    // calculate final values
    out[0] = scale0 * ax + scale1 * bx;
    out[1] = scale0 * ay + scale1 * by;
    out[2] = scale0 * az + scale1 * bz;
    out[3] = scale0 * aw + scale1 * bw;

    return out;
};

/**
 * Calculates the inverse of a quat
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a quat to calculate inverse of
 * @returns {quat} out
 */
quat.invert = function(out, a) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
        invDot = dot ? 1.0/dot : 0;

    // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0

    out[0] = -a0*invDot;
    out[1] = -a1*invDot;
    out[2] = -a2*invDot;
    out[3] = a3*invDot;
    return out;
};

/**
 * Calculates the conjugate of a quat
 * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a quat to calculate conjugate of
 * @returns {quat} out
 */
quat.conjugate = function (out, a) {
    out[0] = -a[0];
    out[1] = -a[1];
    out[2] = -a[2];
    out[3] = a[3];
    return out;
};

/**
 * Calculates the length of a quat
 *
 * @param {quat} a vector to calculate length of
 * @returns {Number} length of a
 * @function
 */
quat.length = glmatrix_vec4.length;

/**
 * Alias for {@link quat.length}
 * @function
 */
quat.len = quat.length;

/**
 * Calculates the squared length of a quat
 *
 * @param {quat} a vector to calculate squared length of
 * @returns {Number} squared length of a
 * @function
 */
quat.squaredLength = glmatrix_vec4.squaredLength;

/**
 * Alias for {@link quat.squaredLength}
 * @function
 */
quat.sqrLen = quat.squaredLength;

/**
 * Normalize a quat
 *
 * @param {quat} out the receiving quaternion
 * @param {quat} a quaternion to normalize
 * @returns {quat} out
 * @function
 */
quat.normalize = glmatrix_vec4.normalize;

/**
 * Creates a quaternion from the given 3x3 rotation matrix.
 *
 * NOTE: The resultant quaternion is not normalized, so you should be sure
 * to renormalize the quaternion yourself where necessary.
 *
 * @param {quat} out the receiving quaternion
 * @param {mat3} m rotation matrix
 * @returns {quat} out
 * @function
 */
quat.fromMat3 = function(out, m) {
    // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
    // article "Quaternion Calculus and Fast Animation".
    var fTrace = m[0] + m[4] + m[8];
    var fRoot;

    if ( fTrace > 0.0 ) {
        // |w| > 1/2, may as well choose w > 1/2
        fRoot = Math.sqrt(fTrace + 1.0);  // 2w
        out[3] = 0.5 * fRoot;
        fRoot = 0.5/fRoot;  // 1/(4w)
        out[0] = (m[5]-m[7])*fRoot;
        out[1] = (m[6]-m[2])*fRoot;
        out[2] = (m[1]-m[3])*fRoot;
    } else {
        // |w| <= 1/2
        var i = 0;
        if ( m[4] > m[0] )
          i = 1;
        if ( m[8] > m[i*3+i] )
          i = 2;
        var j = (i+1)%3;
        var k = (i+2)%3;

        fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
        out[i] = 0.5 * fRoot;
        fRoot = 0.5 / fRoot;
        out[3] = (m[j*3+k] - m[k*3+j]) * fRoot;
        out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
        out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
    }

    return out;
};

/* harmony default export */ const glmatrix_quat = (quat);
;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Matrix4.js






/**
 * @constructor
 * @alias clay.Matrix4
 */
var Matrix4 = function() {

    this._axisX = new math_Vector3();
    this._axisY = new math_Vector3();
    this._axisZ = new math_Vector3();

    /**
     * Storage of Matrix4
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Matrix4#
     */
    this.array = glmatrix_mat4.create();

    /**
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Matrix4#
     */
    this._dirty = true;
};

Matrix4.prototype = {

    constructor: Matrix4,

    /**
     * Set components from array
     * @param  {Float32Array|number[]} arr
     */
    setArray: function (arr) {
        for (var i = 0; i < this.array.length; i++) {
            this.array[i] = arr[i];
        }
        this._dirty = true;
        return this;
    },
    /**
     * Calculate the adjugate of self, in-place
     * @return {clay.Matrix4}
     */
    adjoint: function() {
        glmatrix_mat4.adjoint(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Matrix4
     * @return {clay.Matrix4}
     */
    clone: function() {
        return (new Matrix4()).copy(this);
    },

    /**
     * Copy from b
     * @param  {clay.Matrix4} b
     * @return {clay.Matrix4}
     */
    copy: function(a) {
        glmatrix_mat4.copy(this.array, a.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate matrix determinant
     * @return {number}
     */
    determinant: function() {
        return glmatrix_mat4.determinant(this.array);
    },

    /**
     * Set upper 3x3 part from quaternion
     * @param  {clay.Quaternion} q
     * @return {clay.Matrix4}
     */
    fromQuat: function(q) {
        glmatrix_mat4.fromQuat(this.array, q.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set from a quaternion rotation and a vector translation
     * @param  {clay.Quaternion} q
     * @param  {clay.Vector3} v
     * @return {clay.Matrix4}
     */
    fromRotationTranslation: function(q, v) {
        glmatrix_mat4.fromRotationTranslation(this.array, q.array, v.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set from Matrix2d, it is used when converting a 2d shape to 3d space.
     * In 3d space it is equivalent to ranslate on xy plane and rotate about z axis
     * @param  {clay.Matrix2d} m2d
     * @return {clay.Matrix4}
     */
    fromMat2d: function(m2d) {
        Matrix4.fromMat2d(this, m2d);
        return this;
    },

    /**
     * Set from frustum bounds
     * @param  {number} left
     * @param  {number} right
     * @param  {number} bottom
     * @param  {number} top
     * @param  {number} near
     * @param  {number} far
     * @return {clay.Matrix4}
     */
    frustum: function (left, right, bottom, top, near, far) {
        glmatrix_mat4.frustum(this.array, left, right, bottom, top, near, far);
        this._dirty = true;
        return this;
    },

    /**
     * Set to a identity matrix
     * @return {clay.Matrix4}
     */
    identity: function() {
        glmatrix_mat4.identity(this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Invert self
     * @return {clay.Matrix4}
     */
    invert: function() {
        glmatrix_mat4.invert(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set as a matrix with the given eye position, focal point, and up axis
     * @param  {clay.Vector3} eye
     * @param  {clay.Vector3} center
     * @param  {clay.Vector3} up
     * @return {clay.Matrix4}
     */
    lookAt: function(eye, center, up) {
        glmatrix_mat4.lookAt(this.array, eye.array, center.array, up.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for mutiply
     * @param  {clay.Matrix4} b
     * @return {clay.Matrix4}
     */
    mul: function(b) {
        glmatrix_mat4.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiplyLeft
     * @param  {clay.Matrix4} a
     * @return {clay.Matrix4}
     */
    mulLeft: function(a) {
        glmatrix_mat4.mul(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply self and b
     * @param  {clay.Matrix4} b
     * @return {clay.Matrix4}
     */
    multiply: function(b) {
        glmatrix_mat4.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply a and self, a is on the left
     * @param  {clay.Matrix3} a
     * @return {clay.Matrix3}
     */
    multiplyLeft: function(a) {
        glmatrix_mat4.multiply(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set as a orthographic projection matrix
     * @param  {number} left
     * @param  {number} right
     * @param  {number} bottom
     * @param  {number} top
     * @param  {number} near
     * @param  {number} far
     * @return {clay.Matrix4}
     */
    ortho: function(left, right, bottom, top, near, far) {
        glmatrix_mat4.ortho(this.array, left, right, bottom, top, near, far);
        this._dirty = true;
        return this;
    },
    /**
     * Set as a perspective projection matrix
     * @param  {number} fovy
     * @param  {number} aspect
     * @param  {number} near
     * @param  {number} far
     * @return {clay.Matrix4}
     */
    perspective: function(fovy, aspect, near, far) {
        glmatrix_mat4.perspective(this.array, fovy, aspect, near, far);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by rad about axis.
     * Equal to right-multiply a rotaion matrix
     * @param  {number}   rad
     * @param  {clay.Vector3} axis
     * @return {clay.Matrix4}
     */
    rotate: function(rad, axis) {
        glmatrix_mat4.rotate(this.array, this.array, rad, axis.array);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about X axis.
     * Equal to right-multiply a rotaion matrix
     * @param {number} rad
     * @return {clay.Matrix4}
     */
    rotateX: function(rad) {
        glmatrix_mat4.rotateX(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about Y axis.
     * Equal to right-multiply a rotaion matrix
     * @param {number} rad
     * @return {clay.Matrix4}
     */
    rotateY: function(rad) {
        glmatrix_mat4.rotateY(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about Z axis.
     * Equal to right-multiply a rotaion matrix
     * @param {number} rad
     * @return {clay.Matrix4}
     */
    rotateZ: function(rad) {
        glmatrix_mat4.rotateZ(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self by s
     * Equal to right-multiply a scale matrix
     * @param  {clay.Vector3}  s
     * @return {clay.Matrix4}
     */
    scale: function(v) {
        glmatrix_mat4.scale(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },

    /**
     * Translate self by v.
     * Equal to right-multiply a translate matrix
     * @param  {clay.Vector3}  v
     * @return {clay.Matrix4}
     */
    translate: function(v) {
        glmatrix_mat4.translate(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transpose self, in-place.
     * @return {clay.Matrix2}
     */
    transpose: function() {
        glmatrix_mat4.transpose(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Decompose a matrix to SRT
     * @param {clay.Vector3} [scale]
     * @param {clay.Quaternion} rotation
     * @param {clay.Vector} position
     * @see http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.decompose.aspx
     */
    decomposeMatrix: (function() {

        var x = glmatrix_vec3.create();
        var y = glmatrix_vec3.create();
        var z = glmatrix_vec3.create();

        var m3 = glmatrix_mat3.create();

        return function(scale, rotation, position) {

            var el = this.array;
            glmatrix_vec3.set(x, el[0], el[1], el[2]);
            glmatrix_vec3.set(y, el[4], el[5], el[6]);
            glmatrix_vec3.set(z, el[8], el[9], el[10]);

            var sx = glmatrix_vec3.length(x);
            var sy = glmatrix_vec3.length(y);
            var sz = glmatrix_vec3.length(z);

            // if determine is negative, we need to invert one scale
            var det = this.determinant();
            if (det < 0) {
                sx = -sx;
            }

            if (scale) {
                scale.set(sx, sy, sz);
            }

            position.set(el[12], el[13], el[14]);

            glmatrix_mat3.fromMat4(m3, el);
            // Not like mat4, mat3 in glmatrix seems to be row-based
            // Seems fixed in gl-matrix 2.2.2
            // https://github.com/toji/gl-matrix/issues/114
            // mat3.transpose(m3, m3);

            m3[0] /= sx;
            m3[1] /= sx;
            m3[2] /= sx;

            m3[3] /= sy;
            m3[4] /= sy;
            m3[5] /= sy;

            m3[6] /= sz;
            m3[7] /= sz;
            m3[8] /= sz;

            glmatrix_quat.fromMat3(rotation.array, m3);
            glmatrix_quat.normalize(rotation.array, rotation.array);

            rotation._dirty = true;
            position._dirty = true;
        };
    })(),

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

var Matrix4_defineProperty = Object.defineProperty;

if (Matrix4_defineProperty) {
    var Matrix4_proto = Matrix4.prototype;
    /**
     * Z Axis of local transform
     * @name z
     * @type {clay.Vector3}
     * @memberOf clay.Matrix4
     * @instance
     */
    Matrix4_defineProperty(Matrix4_proto, 'z', {
        get: function () {
            var el = this.array;
            this._axisZ.set(el[8], el[9], el[10]);
            return this._axisZ;
        },
        set: function (v) {
            // TODO Here has a problem
            // If only set an item of vector will not work
            var el = this.array;
            v = v.array;
            el[8] = v[0];
            el[9] = v[1];
            el[10] = v[2];

            this._dirty = true;
        }
    });

    /**
     * Y Axis of local transform
     * @name y
     * @type {clay.Vector3}
     * @memberOf clay.Matrix4
     * @instance
     */
    Matrix4_defineProperty(Matrix4_proto, 'y', {
        get: function () {
            var el = this.array;
            this._axisY.set(el[4], el[5], el[6]);
            return this._axisY;
        },
        set: function (v) {
            var el = this.array;
            v = v.array;
            el[4] = v[0];
            el[5] = v[1];
            el[6] = v[2];

            this._dirty = true;
        }
    });

    /**
     * X Axis of local transform
     * @name x
     * @type {clay.Vector3}
     * @memberOf clay.Matrix4
     * @instance
     */
    Matrix4_defineProperty(Matrix4_proto, 'x', {
        get: function () {
            var el = this.array;
            this._axisX.set(el[0], el[1], el[2]);
            return this._axisX;
        },
        set: function (v) {
            var el = this.array;
            v = v.array;
            el[0] = v[0];
            el[1] = v[1];
            el[2] = v[2];

            this._dirty = true;
        }
    })
}

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix4}
 */
Matrix4.adjoint = function(out, a) {
    glmatrix_mat4.adjoint(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix4}
 */
Matrix4.copy = function(out, a) {
    glmatrix_mat4.copy(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} a
 * @return {number}
 */
Matrix4.determinant = function(a) {
    return glmatrix_mat4.determinant(a.array);
};

/**
 * @param  {clay.Matrix4} out
 * @return {clay.Matrix4}
 */
Matrix4.identity = function(out) {
    glmatrix_mat4.identity(out.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {number}  left
 * @param  {number}  right
 * @param  {number}  bottom
 * @param  {number}  top
 * @param  {number}  near
 * @param  {number}  far
 * @return {clay.Matrix4}
 */
Matrix4.ortho = function(out, left, right, bottom, top, near, far) {
    glmatrix_mat4.ortho(out.array, left, right, bottom, top, near, far);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {number}  fovy
 * @param  {number}  aspect
 * @param  {number}  near
 * @param  {number}  far
 * @return {clay.Matrix4}
 */
Matrix4.perspective = function(out, fovy, aspect, near, far) {
    glmatrix_mat4.perspective(out.array, fovy, aspect, near, far);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Vector3} eye
 * @param  {clay.Vector3} center
 * @param  {clay.Vector3} up
 * @return {clay.Matrix4}
 */
Matrix4.lookAt = function(out, eye, center, up) {
    glmatrix_mat4.lookAt(out.array, eye.array, center.array, up.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix4}
 */
Matrix4.invert = function(out, a) {
    glmatrix_mat4.invert(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {clay.Matrix4} b
 * @return {clay.Matrix4}
 */
Matrix4.mul = function(out, a, b) {
    glmatrix_mat4.mul(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {clay.Matrix4} b
 * @return {clay.Matrix4}
 */
Matrix4.multiply = Matrix4.mul;

/**
 * @param  {clay.Matrix4}    out
 * @param  {clay.Quaternion} q
 * @return {clay.Matrix4}
 */
Matrix4.fromQuat = function(out, q) {
    glmatrix_mat4.fromQuat(out.array, q.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4}    out
 * @param  {clay.Quaternion} q
 * @param  {clay.Vector3}    v
 * @return {clay.Matrix4}
 */
Matrix4.fromRotationTranslation = function(out, q, v) {
    glmatrix_mat4.fromRotationTranslation(out.array, q.array, v.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} m4
 * @param  {clay.Matrix2d} m2d
 * @return {clay.Matrix4}
 */
Matrix4.fromMat2d = function(m4, m2d) {
    m4._dirty = true;
    var m2d = m2d.array;
    var m4 = m4.array;

    m4[0] = m2d[0];
    m4[4] = m2d[2];
    m4[12] = m2d[4];

    m4[1] = m2d[1];
    m4[5] = m2d[3];
    m4[13] = m2d[5];

    return m4;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {number}  rad
 * @param  {clay.Vector3} axis
 * @return {clay.Matrix4}
 */
Matrix4.rotate = function(out, a, rad, axis) {
    glmatrix_mat4.rotate(out.array, a.array, rad, axis.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {number}  rad
 * @return {clay.Matrix4}
 */
Matrix4.rotateX = function(out, a, rad) {
    glmatrix_mat4.rotateX(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {number}  rad
 * @return {clay.Matrix4}
 */
Matrix4.rotateY = function(out, a, rad) {
    glmatrix_mat4.rotateY(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {number}  rad
 * @return {clay.Matrix4}
 */
Matrix4.rotateZ = function(out, a, rad) {
    glmatrix_mat4.rotateZ(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {clay.Vector3} v
 * @return {clay.Matrix4}
 */
Matrix4.scale = function(out, a, v) {
    glmatrix_mat4.scale(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix4}
 */
Matrix4.transpose = function(out, a) {
    glmatrix_mat4.transpose(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix4} out
 * @param  {clay.Matrix4} a
 * @param  {clay.Vector3} v
 * @return {clay.Matrix4}
 */
Matrix4.translate = function(out, a, v) {
    glmatrix_mat4.translate(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Matrix4 = (Matrix4);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Quaternion.js



/**
 * @constructor
 * @alias clay.Quaternion
 * @param {number} x
 * @param {number} y
 * @param {number} z
 * @param {number} w
 */
var Quaternion = function (x, y, z, w) {

    x = x || 0;
    y = y || 0;
    z = z || 0;
    w = w === undefined ? 1 : w;

    /**
     * Storage of Quaternion, read and write of x, y, z, w will change the values in array
     * All methods also operate on the array instead of x, y, z, w components
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Quaternion#
     */
    this.array = glmatrix_quat.fromValues(x, y, z, w);

    /**
     * Dirty flag is used by the Node to determine
     * if the matrix is updated to latest
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Quaternion#
     */
    this._dirty = true;
};

Quaternion.prototype = {

    constructor: Quaternion,

    /**
     * Add b to self
     * @param  {clay.Quaternion} b
     * @return {clay.Quaternion}
     */
    add: function (b) {
        glmatrix_quat.add(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate the w component from x, y, z component
     * @return {clay.Quaternion}
     */
    calculateW: function () {
        glmatrix_quat.calculateW(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y and z components
     * @param  {number}  x
     * @param  {number}  y
     * @param  {number}  z
     * @param  {number}  w
     * @return {clay.Quaternion}
     */
    set: function (x, y, z, w) {
        this.array[0] = x;
        this.array[1] = y;
        this.array[2] = z;
        this.array[3] = w;
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y, z and w components from array
     * @param  {Float32Array|number[]} arr
     * @return {clay.Quaternion}
     */
    setArray: function (arr) {
        this.array[0] = arr[0];
        this.array[1] = arr[1];
        this.array[2] = arr[2];
        this.array[3] = arr[3];

        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Quaternion
     * @return {clay.Quaternion}
     */
    clone: function () {
        return new Quaternion(this.x, this.y, this.z, this.w);
    },

    /**
     * Calculates the conjugate of self If the quaternion is normalized,
     * this function is faster than invert and produces the same result.
     *
     * @return {clay.Quaternion}
     */
    conjugate: function () {
        glmatrix_quat.conjugate(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Copy from b
     * @param  {clay.Quaternion} b
     * @return {clay.Quaternion}
     */
    copy: function (b) {
        glmatrix_quat.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Dot product of self and b
     * @param  {clay.Quaternion} b
     * @return {number}
     */
    dot: function (b) {
        return glmatrix_quat.dot(this.array, b.array);
    },

    /**
     * Set from the given 3x3 rotation matrix
     * @param  {clay.Matrix3} m
     * @return {clay.Quaternion}
     */
    fromMat3: function (m) {
        glmatrix_quat.fromMat3(this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set from the given 4x4 rotation matrix
     * The 4th column and 4th row will be droped
     * @param  {clay.Matrix4} m
     * @return {clay.Quaternion}
     */
    fromMat4: (function () {
        var m3 = glmatrix_mat3.create();
        return function (m) {
            glmatrix_mat3.fromMat4(m3, m.array);
            // TODO Not like mat4, mat3 in glmatrix seems to be row-based
            glmatrix_mat3.transpose(m3, m3);
            glmatrix_quat.fromMat3(this.array, m3);
            this._dirty = true;
            return this;
        };
    })(),

    /**
     * Set to identity quaternion
     * @return {clay.Quaternion}
     */
    identity: function () {
        glmatrix_quat.identity(this.array);
        this._dirty = true;
        return this;
    },
    /**
     * Invert self
     * @return {clay.Quaternion}
     */
    invert: function () {
        glmatrix_quat.invert(this.array, this.array);
        this._dirty = true;
        return this;
    },
    /**
     * Alias of length
     * @return {number}
     */
    len: function () {
        return glmatrix_quat.len(this.array);
    },

    /**
     * Calculate the length
     * @return {number}
     */
    length: function () {
        return glmatrix_quat.length(this.array);
    },

    /**
     * Linear interpolation between a and b
     * @param  {clay.Quaternion} a
     * @param  {clay.Quaternion} b
     * @param  {number}  t
     * @return {clay.Quaternion}
     */
    lerp: function (a, b, t) {
        glmatrix_quat.lerp(this.array, a.array, b.array, t);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiply
     * @param  {clay.Quaternion} b
     * @return {clay.Quaternion}
     */
    mul: function (b) {
        glmatrix_quat.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiplyLeft
     * @param  {clay.Quaternion} a
     * @return {clay.Quaternion}
     */
    mulLeft: function (a) {
        glmatrix_quat.multiply(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Mutiply self and b
     * @param  {clay.Quaternion} b
     * @return {clay.Quaternion}
     */
    multiply: function (b) {
        glmatrix_quat.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Mutiply a and self
     * Quaternion mutiply is not commutative, so the result of mutiplyLeft is different with multiply.
     * @param  {clay.Quaternion} a
     * @return {clay.Quaternion}
     */
    multiplyLeft: function (a) {
        glmatrix_quat.multiply(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Normalize self
     * @return {clay.Quaternion}
     */
    normalize: function () {
        glmatrix_quat.normalize(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about X axis
     * @param {number} rad
     * @return {clay.Quaternion}
     */
    rotateX: function (rad) {
        glmatrix_quat.rotateX(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about Y axis
     * @param {number} rad
     * @return {clay.Quaternion}
     */
    rotateY: function (rad) {
        glmatrix_quat.rotateY(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian about Z axis
     * @param {number} rad
     * @return {clay.Quaternion}
     */
    rotateZ: function (rad) {
        glmatrix_quat.rotateZ(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Sets self to represent the shortest rotation from Vector3 a to Vector3 b.
     * a and b needs to be normalized
     * @param  {clay.Vector3} a
     * @param  {clay.Vector3} b
     * @return {clay.Quaternion}
     */
    rotationTo: function (a, b) {
        glmatrix_quat.rotationTo(this.array, a.array, b.array);
        this._dirty = true;
        return this;
    },
    /**
     * Sets self with values corresponding to the given axes
     * @param {clay.Vector3} view
     * @param {clay.Vector3} right
     * @param {clay.Vector3} up
     * @return {clay.Quaternion}
     */
    setAxes: function (view, right, up) {
        glmatrix_quat.setAxes(this.array, view.array, right.array, up.array);
        this._dirty = true;
        return this;
    },

    /**
     * Sets self with a rotation axis and rotation angle
     * @param {clay.Vector3} axis
     * @param {number} rad
     * @return {clay.Quaternion}
     */
    setAxisAngle: function (axis, rad) {
        glmatrix_quat.setAxisAngle(this.array, axis.array, rad);
        this._dirty = true;
        return this;
    },
    /**
     * Perform spherical linear interpolation between a and b
     * @param  {clay.Quaternion} a
     * @param  {clay.Quaternion} b
     * @param  {number} t
     * @return {clay.Quaternion}
     */
    slerp: function (a, b, t) {
        glmatrix_quat.slerp(this.array, a.array, b.array, t);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for squaredLength
     * @return {number}
     */
    sqrLen: function () {
        return glmatrix_quat.sqrLen(this.array);
    },

    /**
     * Squared length of self
     * @return {number}
     */
    squaredLength: function () {
        return glmatrix_quat.squaredLength(this.array);
    },

    /**
     * Set from euler
     * @param {clay.Vector3} v
     * @param {String} order
     */
    fromEuler: function (v, order) {
        return Quaternion.fromEuler(this, v, order);
    },

    toString: function () {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

var Quaternion_defineProperty = Object.defineProperty;
// Getter and Setter
if (Quaternion_defineProperty) {

    var Quaternion_proto = Quaternion.prototype;
    /**
     * @name x
     * @type {number}
     * @memberOf clay.Quaternion
     * @instance
     */
    Quaternion_defineProperty(Quaternion_proto, 'x', {
        get: function () {
            return this.array[0];
        },
        set: function (value) {
            this.array[0] = value;
            this._dirty = true;
        }
    });

    /**
     * @name y
     * @type {number}
     * @memberOf clay.Quaternion
     * @instance
     */
    Quaternion_defineProperty(Quaternion_proto, 'y', {
        get: function () {
            return this.array[1];
        },
        set: function (value) {
            this.array[1] = value;
            this._dirty = true;
        }
    });

    /**
     * @name z
     * @type {number}
     * @memberOf clay.Quaternion
     * @instance
     */
    Quaternion_defineProperty(Quaternion_proto, 'z', {
        get: function () {
            return this.array[2];
        },
        set: function (value) {
            this.array[2] = value;
            this._dirty = true;
        }
    });

    /**
     * @name w
     * @type {number}
     * @memberOf clay.Quaternion
     * @instance
     */
    Quaternion_defineProperty(Quaternion_proto, 'w', {
        get: function () {
            return this.array[3];
        },
        set: function (value) {
            this.array[3] = value;
            this._dirty = true;
        }
    });
}

// Supply methods that are not in place

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @return {clay.Quaternion}
 */
Quaternion.add = function (out, a, b) {
    glmatrix_quat.add(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {number}     x
 * @param  {number}     y
 * @param  {number}     z
 * @param  {number}     w
 * @return {clay.Quaternion}
 */
Quaternion.set = function (out, x, y, z, w) {
    glmatrix_quat.set(out.array, x, y, z, w);
    out._dirty = true;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} b
 * @return {clay.Quaternion}
 */
Quaternion.copy = function (out, b) {
    glmatrix_quat.copy(out.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @return {clay.Quaternion}
 */
Quaternion.calculateW = function (out, a) {
    glmatrix_quat.calculateW(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @return {clay.Quaternion}
 */
Quaternion.conjugate = function (out, a) {
    glmatrix_quat.conjugate(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @return {clay.Quaternion}
 */
Quaternion.identity = function (out) {
    glmatrix_quat.identity(out.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @return {clay.Quaternion}
 */
Quaternion.invert = function (out, a) {
    glmatrix_quat.invert(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @return {number}
 */
Quaternion.dot = function (a, b) {
    return glmatrix_quat.dot(a.array, b.array);
};

/**
 * @param  {clay.Quaternion} a
 * @return {number}
 */
Quaternion.len = function (a) {
    return glmatrix_quat.length(a.array);
};

// Quaternion.length = Quaternion.len;

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @param  {number}     t
 * @return {clay.Quaternion}
 */
Quaternion.lerp = function (out, a, b, t) {
    glmatrix_quat.lerp(out.array, a.array, b.array, t);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @param  {number}     t
 * @return {clay.Quaternion}
 */
Quaternion.slerp = function (out, a, b, t) {
    glmatrix_quat.slerp(out.array, a.array, b.array, t);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @return {clay.Quaternion}
 */
Quaternion.mul = function (out, a, b) {
    glmatrix_quat.multiply(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {clay.Quaternion} b
 * @return {clay.Quaternion}
 */
Quaternion.multiply = Quaternion.mul;

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {number}     rad
 * @return {clay.Quaternion}
 */
Quaternion.rotateX = function (out, a, rad) {
    glmatrix_quat.rotateX(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {number}     rad
 * @return {clay.Quaternion}
 */
Quaternion.rotateY = function (out, a, rad) {
    glmatrix_quat.rotateY(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @param  {number}     rad
 * @return {clay.Quaternion}
 */
Quaternion.rotateZ = function (out, a, rad) {
    glmatrix_quat.rotateZ(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Vector3}    axis
 * @param  {number}     rad
 * @return {clay.Quaternion}
 */
Quaternion.setAxisAngle = function (out, axis, rad) {
    glmatrix_quat.setAxisAngle(out.array, axis.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Quaternion} a
 * @return {clay.Quaternion}
 */
Quaternion.normalize = function (out, a) {
    glmatrix_quat.normalize(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} a
 * @return {number}
 */
Quaternion.sqrLen = function (a) {
    return glmatrix_quat.sqrLen(a.array);
};

/**
 * @function
 * @param  {clay.Quaternion} a
 * @return {number}
 */
Quaternion.squaredLength = Quaternion.sqrLen;

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Matrix3}    m
 * @return {clay.Quaternion}
 */
Quaternion.fromMat3 = function (out, m) {
    glmatrix_quat.fromMat3(out.array, m.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Vector3}    view
 * @param  {clay.Vector3}    right
 * @param  {clay.Vector3}    up
 * @return {clay.Quaternion}
 */
Quaternion.setAxes = function (out, view, right, up) {
    glmatrix_quat.setAxes(out.array, view.array, right.array, up.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Quaternion} out
 * @param  {clay.Vector3}    a
 * @param  {clay.Vector3}    b
 * @return {clay.Quaternion}
 */
Quaternion.rotationTo = function (out, a, b) {
    glmatrix_quat.rotationTo(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * Set quaternion from euler
 * @param {clay.Quaternion} out
 * @param {clay.Vector3} v
 * @param {String} order
 */
Quaternion.fromEuler = function (out, v, order) {

    out._dirty = true;

    v = v.array;
    var target = out.array;
    var c1 = Math.cos(v[0] / 2);
    var c2 = Math.cos(v[1] / 2);
    var c3 = Math.cos(v[2] / 2);
    var s1 = Math.sin(v[0] / 2);
    var s2 = Math.sin(v[1] / 2);
    var s3 = Math.sin(v[2] / 2);

    var order = (order || 'XYZ').toUpperCase();

    // http://www.mathworks.com/matlabcentral/fileexchange/
    //  20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
    //  content/SpinCalc.m

    switch (order) {
        case 'XYZ':
            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
            break;
        case 'YXZ':
            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
            break;
        case 'ZXY':
            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
            break;
        case 'ZYX':
            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
            break;
        case 'YZX':
            target[0] = s1 * c2 * c3 + c1 * s2 * s3;
            target[1] = c1 * s2 * c3 + s1 * c2 * s3;
            target[2] = c1 * c2 * s3 - s1 * s2 * c3;
            target[3] = c1 * c2 * c3 - s1 * s2 * s3;
            break;
        case 'XZY':
            target[0] = s1 * c2 * c3 - c1 * s2 * s3;
            target[1] = c1 * s2 * c3 - s1 * c2 * s3;
            target[2] = c1 * c2 * s3 + s1 * s2 * c3;
            target[3] = c1 * c2 * c3 + s1 * s2 * s3;
            break;
    }
};

/* harmony default export */ const math_Quaternion = (Quaternion);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/BoundingBox.js



var vec3Set = glmatrix_vec3.set;
var vec3Copy = glmatrix_vec3.copy;

/**
 * Axis aligned bounding box
 * @constructor
 * @alias clay.BoundingBox
 * @param {clay.Vector3} [min]
 * @param {clay.Vector3} [max]
 */
var BoundingBox = function (min, max) {

    /**
     * Minimum coords of bounding box
     * @type {clay.Vector3}
     */
    this.min = min || new math_Vector3(Infinity, Infinity, Infinity);

    /**
     * Maximum coords of bounding box
     * @type {clay.Vector3}
     */
    this.max = max || new math_Vector3(-Infinity, -Infinity, -Infinity);

    this.vertices = null;
};

BoundingBox.prototype = {

    constructor: BoundingBox,
    /**
     * Update min and max coords from a vertices array
     * @param  {array} vertices
     */
    updateFromVertices: function (vertices) {
        if (vertices.length > 0) {
            var min = this.min;
            var max = this.max;
            var minArr = min.array;
            var maxArr = max.array;
            vec3Copy(minArr, vertices[0]);
            vec3Copy(maxArr, vertices[0]);
            for (var i = 1; i < vertices.length; i++) {
                var vertex = vertices[i];

                if (vertex[0] < minArr[0]) { minArr[0] = vertex[0]; }
                if (vertex[1] < minArr[1]) { minArr[1] = vertex[1]; }
                if (vertex[2] < minArr[2]) { minArr[2] = vertex[2]; }

                if (vertex[0] > maxArr[0]) { maxArr[0] = vertex[0]; }
                if (vertex[1] > maxArr[1]) { maxArr[1] = vertex[1]; }
                if (vertex[2] > maxArr[2]) { maxArr[2] = vertex[2]; }
            }
            min._dirty = true;
            max._dirty = true;
        }
    },

    /**
     * Union operation with another bounding box
     * @param  {clay.BoundingBox} bbox
     */
    union: function (bbox) {
        var min = this.min;
        var max = this.max;
        glmatrix_vec3.min(min.array, min.array, bbox.min.array);
        glmatrix_vec3.max(max.array, max.array, bbox.max.array);
        min._dirty = true;
        max._dirty = true;
        return this;
    },

    /**
     * Intersection operation with another bounding box
     * @param  {clay.BoundingBox} bbox
     */
    intersection: function (bbox) {
        var min = this.min;
        var max = this.max;
        glmatrix_vec3.max(min.array, min.array, bbox.min.array);
        glmatrix_vec3.min(max.array, max.array, bbox.max.array);
        min._dirty = true;
        max._dirty = true;
        return this;
    },

    /**
     * If intersect with another bounding box
     * @param  {clay.BoundingBox} bbox
     * @return {boolean}
     */
    intersectBoundingBox: function (bbox) {
        var _min = this.min.array;
        var _max = this.max.array;

        var _min2 = bbox.min.array;
        var _max2 = bbox.max.array;

        return ! (_min[0] > _max2[0] || _min[1] > _max2[1] || _min[2] > _max2[2]
            || _max[0] < _min2[0] || _max[1] < _min2[1] || _max[2] < _min2[2]);
    },

    /**
     * If contain another bounding box entirely
     * @param  {clay.BoundingBox} bbox
     * @return {boolean}
     */
    containBoundingBox: function (bbox) {

        var _min = this.min.array;
        var _max = this.max.array;

        var _min2 = bbox.min.array;
        var _max2 = bbox.max.array;

        return _min[0] <= _min2[0] && _min[1] <= _min2[1] && _min[2] <= _min2[2]
            && _max[0] >= _max2[0] && _max[1] >= _max2[1] && _max[2] >= _max2[2];
    },

    /**
     * If contain point entirely
     * @param  {clay.Vector3} point
     * @return {boolean}
     */
    containPoint: function (p) {
        var _min = this.min.array;
        var _max = this.max.array;

        var _p = p.array;

        return _min[0] <= _p[0] && _min[1] <= _p[1] && _min[2] <= _p[2]
            && _max[0] >= _p[0] && _max[1] >= _p[1] && _max[2] >= _p[2];
    },

    /**
     * If bounding box is finite
     */
    isFinite: function () {
        var _min = this.min.array;
        var _max = this.max.array;
        return isFinite(_min[0]) && isFinite(_min[1]) && isFinite(_min[2])
            && isFinite(_max[0]) && isFinite(_max[1]) && isFinite(_max[2]);
    },

    /**
     * Apply an affine transform matrix to the bounding box
     * @param  {clay.Matrix4} matrix
     */
    applyTransform: function (matrix) {
        this.transformFrom(this, matrix);
    },

    /**
     * Get from another bounding box and an affine transform matrix.
     * @param {clay.BoundingBox} source
     * @param {clay.Matrix4} matrix
     */
    transformFrom: (function () {
        // http://dev.theomader.com/transform-bounding-boxes/
        var xa = glmatrix_vec3.create();
        var xb = glmatrix_vec3.create();
        var ya = glmatrix_vec3.create();
        var yb = glmatrix_vec3.create();
        var za = glmatrix_vec3.create();
        var zb = glmatrix_vec3.create();

        return function (source, matrix) {
            var min = source.min.array;
            var max = source.max.array;

            var m = matrix.array;

            xa[0] = m[0] * min[0]; xa[1] = m[1] * min[0]; xa[2] = m[2] * min[0];
            xb[0] = m[0] * max[0]; xb[1] = m[1] * max[0]; xb[2] = m[2] * max[0];

            ya[0] = m[4] * min[1]; ya[1] = m[5] * min[1]; ya[2] = m[6] * min[1];
            yb[0] = m[4] * max[1]; yb[1] = m[5] * max[1]; yb[2] = m[6] * max[1];

            za[0] = m[8] * min[2]; za[1] = m[9] * min[2]; za[2] = m[10] * min[2];
            zb[0] = m[8] * max[2]; zb[1] = m[9] * max[2]; zb[2] = m[10] * max[2];

            min = this.min.array;
            max = this.max.array;
            min[0] = Math.min(xa[0], xb[0]) + Math.min(ya[0], yb[0]) + Math.min(za[0], zb[0]) + m[12];
            min[1] = Math.min(xa[1], xb[1]) + Math.min(ya[1], yb[1]) + Math.min(za[1], zb[1]) + m[13];
            min[2] = Math.min(xa[2], xb[2]) + Math.min(ya[2], yb[2]) + Math.min(za[2], zb[2]) + m[14];

            max[0] = Math.max(xa[0], xb[0]) + Math.max(ya[0], yb[0]) + Math.max(za[0], zb[0]) + m[12];
            max[1] = Math.max(xa[1], xb[1]) + Math.max(ya[1], yb[1]) + Math.max(za[1], zb[1]) + m[13];
            max[2] = Math.max(xa[2], xb[2]) + Math.max(ya[2], yb[2]) + Math.max(za[2], zb[2]) + m[14];

            this.min._dirty = true;
            this.max._dirty = true;

            return this;
        };
    })(),

    /**
     * Apply a projection matrix to the bounding box
     * @param  {clay.Matrix4} matrix
     */
    applyProjection: function (matrix) {
        var min = this.min.array;
        var max = this.max.array;

        var m = matrix.array;
        // min in min z
        var v10 = min[0];
        var v11 = min[1];
        var v12 = min[2];
        // max in min z
        var v20 = max[0];
        var v21 = max[1];
        var v22 = min[2];
        // max in max z
        var v30 = max[0];
        var v31 = max[1];
        var v32 = max[2];

        if (m[15] === 1) {  // Orthographic projection
            min[0] = m[0] * v10 + m[12];
            min[1] = m[5] * v11 + m[13];
            max[2] = m[10] * v12 + m[14];

            max[0] = m[0] * v30 + m[12];
            max[1] = m[5] * v31 + m[13];
            min[2] = m[10] * v32 + m[14];
        }
        else {
            var w = -1 / v12;
            min[0] = m[0] * v10 * w;
            min[1] = m[5] * v11 * w;
            max[2] = (m[10] * v12 + m[14]) * w;

            w = -1 / v22;
            max[0] = m[0] * v20 * w;
            max[1] = m[5] * v21 * w;

            w = -1 / v32;
            min[2] = (m[10] * v32 + m[14]) * w;
        }
        this.min._dirty = true;
        this.max._dirty = true;

        return this;
    },

    updateVertices: function () {
        var vertices = this.vertices;
        if (!vertices) {
            // Cube vertices
            vertices = [];
            for (var i = 0; i < 8; i++) {
                vertices[i] = glmatrix_vec3.fromValues(0, 0, 0);
            }

            /**
             * Eight coords of bounding box
             * @type {Float32Array[]}
             */
            this.vertices = vertices;
        }
        var min = this.min.array;
        var max = this.max.array;
        //--- min z
        // min x
        vec3Set(vertices[0], min[0], min[1], min[2]);
        vec3Set(vertices[1], min[0], max[1], min[2]);
        // max x
        vec3Set(vertices[2], max[0], min[1], min[2]);
        vec3Set(vertices[3], max[0], max[1], min[2]);

        //-- max z
        vec3Set(vertices[4], min[0], min[1], max[2]);
        vec3Set(vertices[5], min[0], max[1], max[2]);
        vec3Set(vertices[6], max[0], min[1], max[2]);
        vec3Set(vertices[7], max[0], max[1], max[2]);

        return this;
    },
    /**
     * Copy values from another bounding box
     * @param  {clay.BoundingBox} bbox
     */
    copy: function (bbox) {
        var min = this.min;
        var max = this.max;
        vec3Copy(min.array, bbox.min.array);
        vec3Copy(max.array, bbox.max.array);
        min._dirty = true;
        max._dirty = true;
        return this;
    },

    /**
     * Clone a new bounding box
     * @return {clay.BoundingBox}
     */
    clone: function () {
        var boundingBox = new BoundingBox();
        boundingBox.copy(this);
        return boundingBox;
    }
};

/* harmony default export */ const math_BoundingBox = (BoundingBox);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Node.js







var nameId = 0;

/**
 * @constructor clay.Node
 * @extends clay.core.Base
 */
var Node = core_Base.extend(/** @lends clay.Node# */{
    /**
     * Scene node name
     * @type {string}
     */
    name: '',

    /**
     * Position relative to its parent node. aka translation.
     * @type {clay.Vector3}
     */
    position: null,

    /**
     * Rotation relative to its parent node. Represented by a quaternion
     * @type {clay.Quaternion}
     */
    rotation: null,

    /**
     * Scale relative to its parent node
     * @type {clay.Vector3}
     */
    scale: null,

    /**
     * Affine transform matrix relative to its root scene.
     * @type {clay.Matrix4}
     */
    worldTransform: null,

    /**
     * Affine transform matrix relative to its parent node.
     * Composited with position, rotation and scale.
     * @type {clay.Matrix4}
     */
    localTransform: null,

    /**
     * If the local transform is update from SRT(scale, rotation, translation, which is position here) each frame
     * @type {boolean}
     */
    autoUpdateLocalTransform: true,

    /**
     * Parent of current scene node
     * @type {?clay.Node}
     * @private
     */
    _parent: null,
    /**
     * The root scene mounted. Null if it is a isolated node
     * @type {?clay.Scene}
     * @private
     */
    _scene: null,
    /**
     * @type {boolean}
     * @private
     */
    _needsUpdateWorldTransform: true,
    /**
     * @type {boolean}
     * @private
     */
    _inIterating: false,

    // Depth for transparent list sorting
    __depth: 0

}, function () {

    if (!this.name) {
        this.name = (this.type || 'NODE') + '_' + (nameId++);
    }

    if (!this.position) {
        this.position = new math_Vector3();
    }
    if (!this.rotation) {
        this.rotation = new math_Quaternion();
    }
    if (!this.scale) {
        this.scale = new math_Vector3(1, 1, 1);
    }

    this.worldTransform = new math_Matrix4();
    this.localTransform = new math_Matrix4();

    this._children = [];

},
/**@lends clay.Node.prototype. */
{

    /**
     * @type {?clay.Vector3}
     * @instance
     */
    target: null,
    /**
     * If node and its chilren invisible
     * @type {boolean}
     * @instance
     */
    invisible: false,

    /**
     * If Node is a skinned mesh
     * @return {boolean}
     */
    isSkinnedMesh: function () {
        return false;
    },
    /**
     * Return true if it is a renderable scene node, like Mesh and ParticleSystem
     * @return {boolean}
     */
    isRenderable: function () {
        return false;
    },

    /**
     * Set the name of the scene node
     * @param {string} name
     */
    setName: function (name) {
        var scene = this._scene;
        if (scene) {
            var nodeRepository = scene._nodeRepository;
            delete nodeRepository[this.name];
            nodeRepository[name] = this;
        }
        this.name = name;
    },

    /**
     * Add a child node
     * @param {clay.Node} node
     */
    add: function (node) {
        var originalParent = node._parent;
        if (originalParent === this) {
            return;
        }
        if (originalParent) {
            originalParent.remove(node);
        }
        node._parent = this;
        this._children.push(node);

        var scene = this._scene;
        if (scene && scene !== node.scene) {
            node.traverse(this._addSelfToScene, this);
        }
        // Mark children needs update transform
        // In case child are remove and added again after parent moved
        node._needsUpdateWorldTransform = true;
    },

    /**
     * Remove the given child scene node
     * @param {clay.Node} node
     */
    remove: function (node) {
        var children = this._children;
        var idx = children.indexOf(node);
        if (idx < 0) {
            return;
        }

        children.splice(idx, 1);
        node._parent = null;

        if (this._scene) {
            node.traverse(this._removeSelfFromScene, this);
        }
    },

    /**
     * Remove all children
     */
    removeAll: function () {
        var children = this._children;

        for (var idx = 0; idx < children.length; idx++) {
            children[idx]._parent = null;

            if (this._scene) {
                children[idx].traverse(this._removeSelfFromScene, this);
            }
        }

        this._children = [];
    },

    /**
     * Get the scene mounted
     * @return {clay.Scene}
     */
    getScene: function () {
        return this._scene;
    },

    /**
     * Get parent node
     * @return {clay.Scene}
     */
    getParent: function () {
        return this._parent;
    },

    _removeSelfFromScene: function (descendant) {
        descendant._scene.removeFromScene(descendant);
        descendant._scene = null;
    },

    _addSelfToScene: function (descendant) {
        this._scene.addToScene(descendant);
        descendant._scene = this._scene;
    },

    /**
     * Return true if it is ancestor of the given scene node
     * @param {clay.Node} node
     */
    isAncestor: function (node) {
        var parent = node._parent;
        while(parent) {
            if (parent === this) {
                return true;
            }
            parent = parent._parent;
        }
        return false;
    },

    /**
     * Get a new created array of all children nodes
     * @return {clay.Node[]}
     */
    children: function () {
        return this._children.slice();
    },

    /**
     * Get child scene node at given index.
     * @param {number} idx
     * @return {clay.Node}
     */
    childAt: function (idx) {
        return this._children[idx];
    },

    /**
     * Get first child with the given name
     * @param {string} name
     * @return {clay.Node}
     */
    getChildByName: function (name) {
        var children = this._children;
        for (var i = 0; i < children.length; i++) {
            if (children[i].name === name) {
                return children[i];
            }
        }
    },

    /**
     * Get first descendant have the given name
     * @param {string} name
     * @return {clay.Node}
     */
    getDescendantByName: function (name) {
        var children = this._children;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.name === name) {
                return child;
            } else {
                var res = child.getDescendantByName(name);
                if (res) {
                    return res;
                }
            }
        }
    },

    /**
     * Query descendant node by path
     * @param {string} path
     * @return {clay.Node}
     * @example
     *  node.queryNode('root/parent/child');
     */
    queryNode: function (path) {
        if (!path) {
            return;
        }
        // TODO Name have slash ?
        var pathArr = path.split('/');
        var current = this;
        for (var i = 0; i < pathArr.length; i++) {
            var name = pathArr[i];
            // Skip empty
            if (!name) {
                continue;
            }
            var found = false;
            var children = current._children;
            for (var j = 0; j < children.length; j++) {
                var child = children[j];
                if (child.name === name) {
                    current = child;
                    found = true;
                    break;
                }
            }
            // Early return if not found
            if (!found) {
                return;
            }
        }

        return current;
    },

    /**
     * Get query path, relative to rootNode(default is scene)
     * @param {clay.Node} [rootNode]
     * @return {string}
     */
    getPath: function (rootNode) {
        if (!this._parent) {
            return '/';
        }

        var current = this._parent;
        var path = this.name;
        while (current._parent) {
            path = current.name + '/' + path;
            if (current._parent == rootNode) {
                break;
            }
            current = current._parent;
        }
        if (!current._parent && rootNode) {
            return null;
        }
        return path;
    },

    /**
     * Depth first traverse all its descendant scene nodes.
     *
     * **WARN** Don't do `add`, `remove` operation in the callback during traverse.
     * @param {Function} callback
     * @param {Node} [context]
     */
    traverse: function (callback, context) {
        callback.call(context, this);
        var _children = this._children;
        for(var i = 0, len = _children.length; i < len; i++) {
            _children[i].traverse(callback, context);
        }
    },

    /**
     * Traverse all children nodes.
     *
     * **WARN** DON'T do `add`, `remove` operation in the callback during iteration.
     *
     * @param {Function} callback
     * @param {Node} [context]
     */
    eachChild: function (callback, context) {
        var _children = this._children;
        for(var i = 0, len = _children.length; i < len; i++) {
            var child = _children[i];
            callback.call(context, child, i);
        }
    },

    /**
     * Set the local transform and decompose to SRT
     * @param {clay.Matrix4} matrix
     */
    setLocalTransform: function (matrix) {
        glmatrix_mat4.copy(this.localTransform.array, matrix.array);
        this.decomposeLocalTransform();
    },

    /**
     * Decompose the local transform to SRT
     */
    decomposeLocalTransform: function (keepScale) {
        var scale = !keepScale ? this.scale: null;
        this.localTransform.decomposeMatrix(scale, this.rotation, this.position);
    },

    /**
     * Set the world transform and decompose to SRT
     * @param {clay.Matrix4} matrix
     */
    setWorldTransform: function (matrix) {
        glmatrix_mat4.copy(this.worldTransform.array, matrix.array);
        this.decomposeWorldTransform();
    },

    /**
     * Decompose the world transform to SRT
     * @function
     */
    decomposeWorldTransform: (function () {

        var tmp = glmatrix_mat4.create();

        return function (keepScale) {
            var localTransform = this.localTransform;
            var worldTransform = this.worldTransform;
            // Assume world transform is updated
            if (this._parent) {
                glmatrix_mat4.invert(tmp, this._parent.worldTransform.array);
                glmatrix_mat4.multiply(localTransform.array, tmp, worldTransform.array);
            } else {
                glmatrix_mat4.copy(localTransform.array, worldTransform.array);
            }
            var scale = !keepScale ? this.scale: null;
            localTransform.decomposeMatrix(scale, this.rotation, this.position);
        };
    })(),

    transformNeedsUpdate: function () {
        return this.position._dirty
            || this.rotation._dirty
            || this.scale._dirty;
    },

    /**
     * Update local transform from SRT
     * Notice that local transform will not be updated if _dirty mark of position, rotation, scale is all false
     */
    updateLocalTransform: function () {
        var position = this.position;
        var rotation = this.rotation;
        var scale = this.scale;

        if (this.transformNeedsUpdate()) {
            var m = this.localTransform.array;

            // Transform order, scale->rotation->position
            glmatrix_mat4.fromRotationTranslation(m, rotation.array, position.array);

            glmatrix_mat4.scale(m, m, scale.array);

            rotation._dirty = false;
            scale._dirty = false;
            position._dirty = false;

            this._needsUpdateWorldTransform = true;
        }
    },

    /**
     * Update world transform, assume its parent world transform have been updated
     * @private
     */
    _updateWorldTransformTopDown: function () {
        var localTransform = this.localTransform.array;
        var worldTransform = this.worldTransform.array;
        if (this._parent) {
            glmatrix_mat4.multiplyAffine(
                worldTransform,
                this._parent.worldTransform.array,
                localTransform
            );
        }
        else {
            glmatrix_mat4.copy(worldTransform, localTransform);
        }
    },

    /**
     * Update world transform before whole scene is updated.
     */
    updateWorldTransform: function () {
        // Find the root node which transform needs update;
        var rootNodeIsDirty = this;
        while (rootNodeIsDirty && rootNodeIsDirty.getParent()
            && rootNodeIsDirty.getParent().transformNeedsUpdate()
        ) {
            rootNodeIsDirty = rootNodeIsDirty.getParent();
        }
        rootNodeIsDirty.update();
    },

    /**
     * Update local transform and world transform recursively
     * @param {boolean} forceUpdateWorld
     */
    update: function (forceUpdateWorld) {
        if (this.autoUpdateLocalTransform) {
            this.updateLocalTransform();
        }
        else {
            // Transform is manually setted
            forceUpdateWorld = true;
        }

        if (forceUpdateWorld || this._needsUpdateWorldTransform) {
            this._updateWorldTransformTopDown();
            forceUpdateWorld = true;
            this._needsUpdateWorldTransform = false;
        }

        var children = this._children;
        for(var i = 0, len = children.length; i < len; i++) {
            children[i].update(forceUpdateWorld);
        }
    },

    /**
     * Get bounding box of node
     * @param  {Function} [filter]
     * @param  {clay.BoundingBox} [out]
     * @return {clay.BoundingBox}
     */
    // TODO Skinning
    getBoundingBox: (function () {
        function defaultFilter (el) {
            return !el.invisible && el.geometry;
        }
        var tmpBBox = new math_BoundingBox();
        var tmpMat4 = new math_Matrix4();
        var invWorldTransform = new math_Matrix4();
        return function (filter, out) {
            out = out || new math_BoundingBox();
            filter = filter || defaultFilter;

            if (this._parent) {
                math_Matrix4.invert(invWorldTransform, this._parent.worldTransform);
            }
            else {
                math_Matrix4.identity(invWorldTransform);
            }

            this.traverse(function (mesh) {
                if (mesh.geometry && mesh.geometry.boundingBox) {
                    tmpBBox.copy(mesh.geometry.boundingBox);
                    math_Matrix4.multiply(tmpMat4, invWorldTransform, mesh.worldTransform);
                    tmpBBox.applyTransform(tmpMat4);
                    out.union(tmpBBox);
                }
            }, this, defaultFilter);

            return out;
        };
    })(),

    /**
     * Get world position, extracted from world transform
     * @param  {clay.Vector3} [out]
     * @return {clay.Vector3}
     */
    getWorldPosition: function (out) {
        // PENDING
        if (this.transformNeedsUpdate()) {
            this.updateWorldTransform();
        }
        var m = this.worldTransform.array;
        if (out) {
            var arr = out.array;
            arr[0] = m[12];
            arr[1] = m[13];
            arr[2] = m[14];
            return out;
        }
        else {
            return new math_Vector3(m[12], m[13], m[14]);
        }
    },

    /**
     * Clone a new node
     * @return {Node}
     */
    clone: function () {
        var node = new this.constructor();

        var children = this._children;

        node.setName(this.name);
        node.position.copy(this.position);
        node.rotation.copy(this.rotation);
        node.scale.copy(this.scale);

        for (var i = 0; i < children.length; i++) {
            node.add(children[i].clone());
        }

        return node;
    },

    /**
     * Rotate the node around a axis by angle degrees, axis passes through point
     * @param {clay.Vector3} point Center point
     * @param {clay.Vector3} axis  Center axis
     * @param {number}       angle Rotation angle
     * @see http://docs.unity3d.com/Documentation/ScriptReference/Transform.RotateAround.html
     * @function
     */
    rotateAround: (function () {
        var v = new math_Vector3();
        var RTMatrix = new math_Matrix4();

        // TODO improve performance
        return function (point, axis, angle) {

            v.copy(this.position).subtract(point);

            var localTransform = this.localTransform;
            localTransform.identity();
            // parent node
            localTransform.translate(point);
            localTransform.rotate(angle, axis);

            RTMatrix.fromRotationTranslation(this.rotation, v);
            localTransform.multiply(RTMatrix);
            localTransform.scale(this.scale);

            this.decomposeLocalTransform();
            this._needsUpdateWorldTransform = true;
        };
    })(),

    /**
     * @param {clay.Vector3} target
     * @param {clay.Vector3} [up]
     * @see http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
     * @function
     */
    lookAt: (function () {
        var m = new math_Matrix4();
        return function (target, up) {
            m.lookAt(this.position, target, up || this.localTransform.y).invert();
            this.setLocalTransform(m);

            this.target = target;
        };
    })()
});

/* harmony default export */ const src_Node = (Node);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Renderable.js



/**
 * @constructor
 * @alias clay.Renderable
 * @extends clay.Node
 */
var Renderable = src_Node.extend(/** @lends clay.Renderable# */ {
    /**
     * @type {clay.Material}
     */
    material: null,

    /**
     * @type {clay.Geometry}
     */
    geometry: null,

    /**
     * @type {number}
     */
    mode: glenum.TRIANGLES,

    _renderInfo: null
},
/** @lends clay.Renderable.prototype */
{

    __program: null,

    /**
     * Group of received light.
     */
    lightGroup: 0,
    /**
     * Render order, Nodes with smaller value renders before nodes with larger values.
     * @type {Number}
     */
    renderOrder: 0,

    /**
     * Used when mode is LINES, LINE_STRIP or LINE_LOOP
     * @type {number}
     */
    // lineWidth: 1,

    /**
     * If enable culling
     * @type {boolean}
     */
    culling: true,
    /**
     * Specify which side of polygon will be culled.
     * Possible values:
     *  + {@link clay.Renderable.BACK}
     *  + {@link clay.Renderable.FRONT}
     *  + {@link clay.Renderable.FRONT_AND_BACK}
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace
     * @type {number}
     */
    cullFace: glenum.BACK,
    /**
     * Specify which side is front face.
     * Possible values:
     *  + {@link clay.Renderable.CW}
     *  + {@link clay.Renderable.CCW}
     * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace
     * @type {number}
     */
    frontFace: glenum.CCW,

    /**
     * If enable software frustum culling
     * @type {boolean}
     */
    frustumCulling: true,
    /**
     * @type {boolean}
     */
    receiveShadow: true,
    /**
     * @type {boolean}
     */
    castShadow: true,
    /**
     * @type {boolean}
     */
    ignorePicking: false,
    /**
     * @type {boolean}
     */
    ignorePreZ: false,

    /**
     * @type {boolean}
     */
    ignoreGBuffer: false,

    /**
     * @return {boolean}
     */
    isRenderable: function() {
        // TODO Shader ?
        return this.geometry && this.material && this.material.shader && !this.invisible
            && this.geometry.vertexCount > 0;
    },

    /**
     * Before render hook
     * @type {Function}
     */
    beforeRender: function (_gl) {},

    /**
     * Before render hook
     * @type {Function}
     */
    afterRender: function (_gl, renderStat) {},

    getBoundingBox: function (filter, out) {
        out = src_Node.prototype.getBoundingBox.call(this, filter, out);
        if (this.geometry && this.geometry.boundingBox) {
            out.union(this.geometry.boundingBox);
        }

        return out;
    },

    /**
     * Clone a new renderable
     * @function
     * @return {clay.Renderable}
     */
    clone: (function() {
        var properties = [
            'castShadow', 'receiveShadow',
            'mode', 'culling', 'cullFace', 'frontFace',
            'frustumCulling',
            'renderOrder', 'lineWidth',
            'ignorePicking', 'ignorePreZ', 'ignoreGBuffer'
        ];
        return function() {
            var renderable = src_Node.prototype.clone.call(this);

            renderable.geometry = this.geometry;
            renderable.material = this.material;

            for (var i = 0; i < properties.length; i++) {
                var name = properties[i];
                // Try not to overwrite the prototype property
                if (renderable[name] !== this[name]) {
                    renderable[name] = this[name];
                }
            }

            return renderable;
        };
    })()
});

/**
 * @type {number}
 */
Renderable.POINTS = glenum.POINTS;
/**
 * @type {number}
 */
Renderable.LINES = glenum.LINES;
/**
 * @type {number}
 */
Renderable.LINE_LOOP = glenum.LINE_LOOP;
/**
 * @type {number}
 */
Renderable.LINE_STRIP = glenum.LINE_STRIP;
/**
 * @type {number}
 */
Renderable.TRIANGLES = glenum.TRIANGLES;
/**
 * @type {number}
 */
Renderable.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP;
/**
 * @type {number}
 */
Renderable.TRIANGLE_FAN = glenum.TRIANGLE_FAN;
/**
 * @type {number}
 */
Renderable.BACK = glenum.BACK;
/**
 * @type {number}
 */
Renderable.FRONT = glenum.FRONT;
/**
 * @type {number}
 */
Renderable.FRONT_AND_BACK = glenum.FRONT_AND_BACK;
/**
 * @type {number}
 */
Renderable.CW = glenum.CW;
/**
 * @type {number}
 */
Renderable.CCW = glenum.CCW;

/* harmony default export */ const src_Renderable = (Renderable);

;// CONCATENATED MODULE: ./node_modules/claygl/src/picking/RayPicking.js









/**
 * @constructor clay.picking.RayPicking
 * @extends clay.core.Base
 */
var RayPicking = core_Base.extend(/** @lends clay.picking.RayPicking# */{
    /**
     * Target scene
     * @type {clay.Scene}
     */
    scene: null,
    /**
     * Target camera
     * @type {clay.Camera}
     */
    camera: null,
    /**
     * Target renderer
     * @type {clay.Renderer}
     */
    renderer: null
}, function () {
    this._ray = new math_Ray();
    this._ndc = new math_Vector2();
},
/** @lends clay.picking.RayPicking.prototype */
{

    /**
     * Pick the nearest intersection object in the scene
     * @param  {number} x Mouse position x
     * @param  {number} y Mouse position y
     * @param  {boolean} [forcePickAll=false] ignore ignorePicking
     * @return {clay.picking.RayPicking~Intersection}
     */
    pick: function (x, y, forcePickAll) {
        var out = this.pickAll(x, y, [], forcePickAll);
        return out[0] || null;
    },

    /**
     * Pick all intersection objects, wich will be sorted from near to far
     * @param  {number} x Mouse position x
     * @param  {number} y Mouse position y
     * @param  {Array} [output]
     * @param  {boolean} [forcePickAll=false] ignore ignorePicking
     * @return {Array.<clay.picking.RayPicking~Intersection>}
     */
    pickAll: function (x, y, output, forcePickAll) {
        this.renderer.screenToNDC(x, y, this._ndc);
        this.camera.castRay(this._ndc, this._ray);

        output = output || [];

        this._intersectNode(this.scene, output, forcePickAll || false);

        output.sort(this._intersectionCompareFunc);

        return output;
    },

    _intersectNode: function (node, out, forcePickAll) {
        if ((node instanceof src_Renderable) && node.isRenderable()) {
            if ((!node.ignorePicking || forcePickAll)
                && (
                    // Only triangle mesh support ray picking
                    (node.mode === glenum.TRIANGLES && node.geometry.isUseIndices())
                    // Or if geometry has it's own pickByRay, pick, implementation
                    || node.geometry.pickByRay
                    || node.geometry.pick
                )
            ) {
                this._intersectRenderable(node, out);
            }
        }
        for (var i = 0; i < node._children.length; i++) {
            this._intersectNode(node._children[i], out, forcePickAll);
        }
    },

    _intersectRenderable: (function () {

        var v1 = new math_Vector3();
        var v2 = new math_Vector3();
        var v3 = new math_Vector3();
        var ray = new math_Ray();
        var worldInverse = new math_Matrix4();

        return function (renderable, out) {

            var isSkinnedMesh = renderable.isSkinnedMesh();
            ray.copy(this._ray);
            math_Matrix4.invert(worldInverse, renderable.worldTransform);

            // Skinned mesh will ignore the world transform.
            if (!isSkinnedMesh) {
                ray.applyTransform(worldInverse);
            }

            var geometry = renderable.geometry;

            var bbox = isSkinnedMesh ? renderable.skeleton.boundingBox : geometry.boundingBox;

            if (bbox && !ray.intersectBoundingBox(bbox)) {
                return;
            }
            // Use user defined picking algorithm
            if (geometry.pick) {
                geometry.pick(
                    this._ndc.x, this._ndc.y,
                    this.renderer,
                    this.camera,
                    renderable, out
                );
                return;
            }
            // Use user defined ray picking algorithm
            else if (geometry.pickByRay) {
                geometry.pickByRay(ray, renderable, out);
                return;
            }

            var cullBack = (renderable.cullFace === glenum.BACK && renderable.frontFace === glenum.CCW)
                        || (renderable.cullFace === glenum.FRONT && renderable.frontFace === glenum.CW);

            var point;
            var indices = geometry.indices;
            var positionAttr = geometry.attributes.position;
            var weightAttr = geometry.attributes.weight;
            var jointAttr = geometry.attributes.joint;
            var skinMatricesArray;
            var skinMatrices = [];
            // Check if valid.
            if (!positionAttr || !positionAttr.value || !indices) {
                return;
            }
            if (isSkinnedMesh) {
                skinMatricesArray = renderable.skeleton.getSubSkinMatrices(renderable.__uid__, renderable.joints);
                for (var i = 0; i < renderable.joints.length; i++) {
                    skinMatrices[i] = skinMatrices[i] || [];
                    for (var k = 0; k < 16; k++) {
                        skinMatrices[i][k] = skinMatricesArray[i * 16 + k];
                    }
                }
                var pos = [];
                var weight = [];
                var joint = [];
                var skinnedPos = [];
                var tmp = [];
                var skinnedPositionAttr = geometry.attributes.skinnedPosition;
                if (!skinnedPositionAttr || !skinnedPositionAttr.value) {
                    geometry.createAttribute('skinnedPosition', 'f', 3);
                    skinnedPositionAttr = geometry.attributes.skinnedPosition;
                    skinnedPositionAttr.init(geometry.vertexCount);
                }
                for (var i = 0; i < geometry.vertexCount; i++) {
                    positionAttr.get(i, pos);
                    weightAttr.get(i, weight);
                    jointAttr.get(i, joint);
                    weight[3] = 1 - weight[0] - weight[1] - weight[2];
                    glmatrix_vec3.set(skinnedPos, 0, 0, 0);
                    for (var k = 0; k < 4; k++) {
                        if (joint[k] >= 0 && weight[k] > 1e-4) {
                            glmatrix_vec3.transformMat4(tmp, pos, skinMatrices[joint[k]]);
                            glmatrix_vec3.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]);
                        }
                    }
                    skinnedPositionAttr.set(i, skinnedPos);
                }
            }

            for (var i = 0; i < indices.length; i += 3) {
                var i1 = indices[i];
                var i2 = indices[i + 1];
                var i3 = indices[i + 2];
                var finalPosAttr = isSkinnedMesh
                    ? geometry.attributes.skinnedPosition
                    : positionAttr;
                finalPosAttr.get(i1, v1.array);
                finalPosAttr.get(i2, v2.array);
                finalPosAttr.get(i3, v3.array);

                if (cullBack) {
                    point = ray.intersectTriangle(v1, v2, v3, renderable.culling);
                }
                else {
                    point = ray.intersectTriangle(v1, v3, v2, renderable.culling);
                }
                if (point) {
                    var pointW = new math_Vector3();
                    if (!isSkinnedMesh) {
                        math_Vector3.transformMat4(pointW, point, renderable.worldTransform);
                    }
                    else {
                        // TODO point maybe not right.
                        math_Vector3.copy(pointW, point);
                    }
                    out.push(new RayPicking.Intersection(
                        point, pointW, renderable, [i1, i2, i3], i / 3,
                        math_Vector3.dist(pointW, this._ray.origin)
                    ));
                }
            }
        };
    })(),

    _intersectionCompareFunc: function (a, b) {
        return a.distance - b.distance;
    }
});

/**
 * @constructor clay.picking.RayPicking~Intersection
 * @param {clay.Vector3} point
 * @param {clay.Vector3} pointWorld
 * @param {clay.Node} target
 * @param {Array.<number>} triangle
 * @param {number} triangleIndex
 * @param {number} distance
 */
RayPicking.Intersection = function (point, pointWorld, target, triangle, triangleIndex, distance) {
    /**
     * Intersection point in local transform coordinates
     * @type {clay.Vector3}
     */
    this.point = point;
    /**
     * Intersection point in world transform coordinates
     * @type {clay.Vector3}
     */
    this.pointWorld = pointWorld;
    /**
     * Intersection scene node
     * @type {clay.Node}
     */
    this.target = target;
    /**
     * Intersection triangle, which is an array of vertex index
     * @type {Array.<number>}
     */
    this.triangle = triangle;
    /**
     * Index of intersection triangle.
     */
    this.triangleIndex = triangleIndex;
    /**
     * Distance from intersection point to ray origin
     * @type {number}
     */
    this.distance = distance;
};

/* harmony default export */ const picking_RayPicking = (RayPicking);

;// CONCATENATED MODULE: ./node_modules/claygl/src/core/Cache.js
var DIRTY_PREFIX = '__dt__';

var Cache = function () {

    this._contextId = 0;

    this._caches = [];

    this._context = {};
};

Cache.prototype = {

    use: function (contextId, documentSchema) {
        var caches = this._caches;
        if (!caches[contextId]) {
            caches[contextId] = {};

            if (documentSchema) {
                caches[contextId] = documentSchema();
            }
        }
        this._contextId = contextId;

        this._context = caches[contextId];
    },

    put: function (key, value) {
        this._context[key] = value;
    },

    get: function (key) {
        return this._context[key];
    },

    dirty: function (field) {
        field = field || '';
        var key = DIRTY_PREFIX + field;
        this.put(key, true);
    },

    dirtyAll: function (field) {
        field = field || '';
        var key = DIRTY_PREFIX + field;
        var caches = this._caches;
        for (var i = 0; i < caches.length; i++) {
            if (caches[i]) {
                caches[i][key] = true;
            }
        }
    },

    fresh: function (field) {
        field = field || '';
        var key = DIRTY_PREFIX + field;
        this.put(key, false);
    },

    freshAll: function (field) {
        field = field || '';
        var key = DIRTY_PREFIX + field;
        var caches = this._caches;
        for (var i = 0; i < caches.length; i++) {
            if (caches[i]) {
                caches[i][key] = false;
            }
        }
    },

    isDirty: function (field) {
        field = field || '';
        var key = DIRTY_PREFIX + field;
        var context = this._context;
        return  !context.hasOwnProperty(key)
            || context[key] === true;
    },

    deleteContext: function (contextId) {
        delete this._caches[contextId];
        this._context = {};
    },

    delete: function (key) {
        delete this._context[key];
    },

    clearAll: function () {
        this._caches = {};
    },

    getContext: function () {
        return this._context;
    },

    eachContext : function (cb, context) {
        var keys = Object.keys(this._caches);
        keys.forEach(function (key) {
            cb && cb.call(context, key);
        });
    },

    miss: function (key) {
        return ! this._context.hasOwnProperty(key);
    }
};

Cache.prototype.constructor = Cache;

/* harmony default export */ const core_Cache = (Cache);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Texture.js
/**
 * Base class for all textures like compressed texture, texture2d, texturecube
 * TODO mapping
 */




/**
 * @constructor
 * @alias clay.Texture
 * @extends clay.core.Base
 */
var Texture = core_Base.extend( /** @lends clay.Texture# */ {
    /**
     * Texture width, readonly when the texture source is image
     * @type {number}
     */
    width: 512,
    /**
     * Texture height, readonly when the texture source is image
     * @type {number}
     */
    height: 512,
    /**
     * Texel data type.
     * Possible values:
     *  + {@link clay.Texture.UNSIGNED_BYTE}
     *  + {@link clay.Texture.HALF_FLOAT}
     *  + {@link clay.Texture.FLOAT}
     *  + {@link clay.Texture.UNSIGNED_INT_24_8_WEBGL}
     *  + {@link clay.Texture.UNSIGNED_INT}
     * @type {number}
     */
    type: glenum.UNSIGNED_BYTE,
    /**
     * Format of texel data
     * Possible values:
     *  + {@link clay.Texture.RGBA}
     *  + {@link clay.Texture.DEPTH_COMPONENT}
     *  + {@link clay.Texture.DEPTH_STENCIL}
     * @type {number}
     */
    format: glenum.RGBA,
    /**
     * Texture wrap. Default to be REPEAT.
     * Possible values:
     *  + {@link clay.Texture.CLAMP_TO_EDGE}
     *  + {@link clay.Texture.REPEAT}
     *  + {@link clay.Texture.MIRRORED_REPEAT}
     * @type {number}
     */
    wrapS: glenum.REPEAT,
    /**
     * Texture wrap. Default to be REPEAT.
     * Possible values:
     *  + {@link clay.Texture.CLAMP_TO_EDGE}
     *  + {@link clay.Texture.REPEAT}
     *  + {@link clay.Texture.MIRRORED_REPEAT}
     * @type {number}
     */
    wrapT: glenum.REPEAT,
    /**
     * Possible values:
     *  + {@link clay.Texture.NEAREST}
     *  + {@link clay.Texture.LINEAR}
     *  + {@link clay.Texture.NEAREST_MIPMAP_NEAREST}
     *  + {@link clay.Texture.LINEAR_MIPMAP_NEAREST}
     *  + {@link clay.Texture.NEAREST_MIPMAP_LINEAR}
     *  + {@link clay.Texture.LINEAR_MIPMAP_LINEAR}
     * @type {number}
     */
    minFilter: glenum.LINEAR_MIPMAP_LINEAR,
    /**
     * Possible values:
     *  + {@link clay.Texture.NEAREST}
     *  + {@link clay.Texture.LINEAR}
     * @type {number}
     */
    magFilter: glenum.LINEAR,
    /**
     * If enable mimap.
     * @type {boolean}
     */
    useMipmap: true,

    /**
     * Anisotropic filtering, enabled if value is larger than 1
     * @see https://developer.mozilla.org/en-US/docs/Web/API/EXT_texture_filter_anisotropic
     * @type {number}
     */
    anisotropic: 1,
    // pixelStorei parameters, not available when texture is used as render target
    // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml
    /**
     * If flip in y axis for given image source
     * @type {boolean}
     * @default true
     */
    flipY: true,

    /**
     * A flag to indicate if texture source is sRGB
     */
    sRGB: true,
    /**
     * @type {number}
     * @default 4
     */
    unpackAlignment: 4,
    /**
     * @type {boolean}
     * @default false
     */
    premultiplyAlpha: false,

    /**
     * Dynamic option for texture like video
     * @type {boolean}
     */
    dynamic: false,

    NPOT: false,

    // PENDING
    // Init it here to avoid deoptimization when it's assigned in application dynamically
    __used: 0

}, function () {
    this._cache = new core_Cache();
},
/** @lends clay.Texture.prototype */
{

    getWebGLTexture: function (renderer) {
        var _gl = renderer.gl;
        var cache = this._cache;
        cache.use(renderer.__uid__);

        if (cache.miss('webgl_texture')) {
            // In a new gl context, create new texture and set dirty true
            cache.put('webgl_texture', _gl.createTexture());
        }
        if (this.dynamic) {
            this.update(renderer);
        }
        else if (cache.isDirty()) {
            this.update(renderer);
            cache.fresh();
        }

        return cache.get('webgl_texture');
    },

    bind: function () {},
    unbind: function () {},

    /**
     * Mark texture is dirty and update in the next frame
     */
    dirty: function () {
        if (this._cache) {
            this._cache.dirtyAll();
        }
    },

    update: function (renderer) {},

    // Update the common parameters of texture
    updateCommon: function (renderer) {
        var _gl = renderer.gl;
        _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, this.flipY);
        _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha);
        _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, this.unpackAlignment);

        // Use of none-power of two texture
        // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences
        if (this.format === glenum.DEPTH_COMPONENT) {
            this.useMipmap = false;
        }

        var sRGBExt = renderer.getGLExtension('EXT_sRGB');
        // Fallback
        if (this.format === Texture.SRGB && !sRGBExt) {
            this.format = Texture.RGB;
        }
        if (this.format === Texture.SRGB_ALPHA && !sRGBExt) {
            this.format = Texture.RGBA;
        }

        this.NPOT = !this.isPowerOfTwo();
    },

    getAvailableWrapS: function () {
        if (this.NPOT) {
            return glenum.CLAMP_TO_EDGE;
        }
        return this.wrapS;
    },
    getAvailableWrapT: function () {
        if (this.NPOT) {
            return glenum.CLAMP_TO_EDGE;
        }
        return this.wrapT;
    },
    getAvailableMinFilter: function () {
        var minFilter = this.minFilter;
        if (this.NPOT || !this.useMipmap) {
            if (minFilter === glenum.NEAREST_MIPMAP_NEAREST ||
                minFilter === glenum.NEAREST_MIPMAP_LINEAR
            ) {
                return glenum.NEAREST;
            }
            else if (minFilter === glenum.LINEAR_MIPMAP_LINEAR ||
                minFilter === glenum.LINEAR_MIPMAP_NEAREST
            ) {
                return glenum.LINEAR;
            }
            else {
                return minFilter;
            }
        }
        else {
            return minFilter;
        }
    },
    getAvailableMagFilter: function () {
        return this.magFilter;
    },

    nextHighestPowerOfTwo: function (x) {
        --x;
        for (var i = 1; i < 32; i <<= 1) {
            x = x | x >> i;
        }
        return x + 1;
    },
    /**
     * @param  {clay.Renderer} renderer
     */
    dispose: function (renderer) {

        var cache = this._cache;

        cache.use(renderer.__uid__);

        var webglTexture = cache.get('webgl_texture');
        if (webglTexture){
            renderer.gl.deleteTexture(webglTexture);
        }
        cache.deleteContext(renderer.__uid__);

    },
    /**
     * Test if image of texture is valid and loaded.
     * @return {boolean}
     */
    isRenderable: function () {},

    /**
     * Test if texture size is power of two
     * @return {boolean}
     */
    isPowerOfTwo: function () {}
});

Object.defineProperty(Texture.prototype, 'width', {
    get: function () {
        return this._width;
    },
    set: function (value) {
        this._width = value;
    }
});
Object.defineProperty(Texture.prototype, 'height', {
    get: function () {
        return this._height;
    },
    set: function (value) {
        this._height = value;
    }
});

/* DataType */

/**
 * @type {number}
 */
Texture.BYTE = glenum.BYTE;
/**
 * @type {number}
 */
Texture.UNSIGNED_BYTE = glenum.UNSIGNED_BYTE;
/**
 * @type {number}
 */
Texture.SHORT = glenum.SHORT;
/**
 * @type {number}
 */
Texture.UNSIGNED_SHORT = glenum.UNSIGNED_SHORT;
/**
 * @type {number}
 */
Texture.INT = glenum.INT;
/**
 * @type {number}
 */
Texture.UNSIGNED_INT = glenum.UNSIGNED_INT;
/**
 * @type {number}
 */
Texture.FLOAT = glenum.FLOAT;
/**
 * @type {number}
 */
Texture.HALF_FLOAT = 0x8D61;

/**
 * UNSIGNED_INT_24_8_WEBGL for WEBGL_depth_texture extension
 * @type {number}
 */
Texture.UNSIGNED_INT_24_8_WEBGL = 34042;

/* PixelFormat */
/**
 * @type {number}
 */
Texture.DEPTH_COMPONENT = glenum.DEPTH_COMPONENT;
/**
 * @type {number}
 */
Texture.DEPTH_STENCIL = glenum.DEPTH_STENCIL;
/**
 * @type {number}
 */
Texture.ALPHA = glenum.ALPHA;
/**
 * @type {number}
 */
Texture.RGB = glenum.RGB;
/**
 * @type {number}
 */
Texture.RGBA = glenum.RGBA;
/**
 * @type {number}
 */
Texture.LUMINANCE = glenum.LUMINANCE;
/**
 * @type {number}
 */
Texture.LUMINANCE_ALPHA = glenum.LUMINANCE_ALPHA;

/**
 * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/
 * @type {number}
 */
Texture.SRGB = 0x8C40;
/**
 * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/
 * @type {number}
 */
Texture.SRGB_ALPHA = 0x8C42;

/* Compressed Texture */
Texture.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0;
Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3;

/* TextureMagFilter */
/**
 * @type {number}
 */
Texture.NEAREST = glenum.NEAREST;
/**
 * @type {number}
 */
Texture.LINEAR = glenum.LINEAR;

/* TextureMinFilter */
/**
 * @type {number}
 */
Texture.NEAREST_MIPMAP_NEAREST = glenum.NEAREST_MIPMAP_NEAREST;
/**
 * @type {number}
 */
Texture.LINEAR_MIPMAP_NEAREST = glenum.LINEAR_MIPMAP_NEAREST;
/**
 * @type {number}
 */
Texture.NEAREST_MIPMAP_LINEAR = glenum.NEAREST_MIPMAP_LINEAR;
/**
 * @type {number}
 */
Texture.LINEAR_MIPMAP_LINEAR = glenum.LINEAR_MIPMAP_LINEAR;

/* TextureWrapMode */
/**
 * @type {number}
 */
Texture.REPEAT = glenum.REPEAT;
/**
 * @type {number}
 */
Texture.CLAMP_TO_EDGE = glenum.CLAMP_TO_EDGE;
/**
 * @type {number}
 */
Texture.MIRRORED_REPEAT = glenum.MIRRORED_REPEAT;


/* harmony default export */ const src_Texture = (Texture);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Mesh.js



/**
 * @constructor clay.Mesh
 * @extends clay.Renderable
 */
var Mesh = src_Renderable.extend(/** @lends clay.Mesh# */ {
    /**
     * Used when it is a skinned mesh
     * @type {clay.Skeleton}
     */
    skeleton: null,
    /**
     * Joints indices Meshes can share the one skeleton instance and each mesh can use one part of joints. Joints indices indicate the index of joint in the skeleton instance
     * @type {number[]}
     */
    joints: null

}, function () {
    if (!this.joints) {
        this.joints = [];
    }
}, {

    /**
     * Offset matrix used for multiple skinned mesh clone sharing one skeleton
     * @type {clay.Matrix4}
     */
    offsetMatrix: null,

    isInstancedMesh: function () { return false; },

    isSkinnedMesh: function () {
        return !!(this.skeleton && this.joints && this.joints.length > 0);
    },

    clone: function () {
        var mesh = src_Renderable.prototype.clone.call(this);
        mesh.skeleton = this.skeleton;
        if (this.joints) {
            mesh.joints = this.joints.slice();
        }
        return mesh;
    }
});

// Enums
Mesh.POINTS = glenum.POINTS;
Mesh.LINES = glenum.LINES;
Mesh.LINE_LOOP = glenum.LINE_LOOP;
Mesh.LINE_STRIP = glenum.LINE_STRIP;
Mesh.TRIANGLES = glenum.TRIANGLES;
Mesh.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP;
Mesh.TRIANGLE_FAN = glenum.TRIANGLE_FAN;

Mesh.BACK = glenum.BACK;
Mesh.FRONT = glenum.FRONT;
Mesh.FRONT_AND_BACK = glenum.FRONT_AND_BACK;
Mesh.CW = glenum.CW;
Mesh.CCW = glenum.CCW;

/* harmony default export */ const src_Mesh = (Mesh);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/util.js
var mathUtil = {};

mathUtil.isPowerOfTwo = function (value) {
    return (value & (value - 1)) === 0;
};

mathUtil.nextPowerOfTwo = function (value) {
    value --;
    value |= value >> 1;
    value |= value >> 2;
    value |= value >> 4;
    value |= value >> 8;
    value |= value >> 16;
    value ++;

    return value;
};

mathUtil.nearestPowerOfTwo = function (value) {
    return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) );
};

/* harmony default export */ const math_util = (mathUtil);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Texture2D.js




var isPowerOfTwo = math_util.isPowerOfTwo;

function nearestPowerOfTwo(val) {
    return Math.pow(2, Math.round(Math.log(val) / Math.LN2));
}
function convertTextureToPowerOfTwo(texture, canvas) {
    // var canvas = document.createElement('canvas');
    var width = nearestPowerOfTwo(texture.width);
    var height = nearestPowerOfTwo(texture.height);
    canvas = canvas || document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    var ctx = canvas.getContext('2d');
    ctx.drawImage(texture.image, 0, 0, width, height);

    return canvas;
}

/**
 * @constructor clay.Texture2D
 * @extends clay.Texture
 *
 * @example
 *     ...
 *     var mat = new clay.Material({
 *         shader: clay.shader.library.get('clay.phong', 'diffuseMap')
 *     });
 *     var diffuseMap = new clay.Texture2D();
 *     diffuseMap.load('assets/textures/diffuse.jpg');
 *     mat.set('diffuseMap', diffuseMap);
 *     ...
 *     diffuseMap.success(function () {
 *         // Wait for the diffuse texture loaded
 *         animation.on('frame', function (frameTime) {
 *             renderer.render(scene, camera);
 *         });
 *     });
 */
var Texture2D = src_Texture.extend(function () {
    return /** @lends clay.Texture2D# */ {
        /**
         * @type {?HTMLImageElement|HTMLCanvasElemnet}
         */
        // TODO mark dirty when assigned.
        image: null,
        /**
         * Pixels data. Will be ignored if image is set.
         * @type {?Uint8Array|Float32Array}
         */
        pixels: null,
        /**
         * @type {Array.<Object>}
         * @example
         *     [{
         *         image: mipmap0,
         *         pixels: null
         *     }, {
         *         image: mipmap1,
         *         pixels: null
         *     }, ....]
         */
        mipmaps: [],

        /**
         * If convert texture to power-of-two
         * @type {boolean}
         */
        convertToPOT: false
    };
}, {

    textureType: 'texture2D',

    update: function (renderer) {

        var _gl = renderer.gl;
        _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture'));

        this.updateCommon(renderer);

        var glFormat = this.format;
        var glType = this.type;

        // Convert to pot is only available when using image/canvas/video element.
        var convertToPOT = !!(this.convertToPOT
            && !this.mipmaps.length && this.image
            && (this.wrapS === src_Texture.REPEAT || this.wrapT === src_Texture.REPEAT)
            && this.NPOT
        );

        _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, convertToPOT ? this.wrapS : this.getAvailableWrapS());
        _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, convertToPOT ? this.wrapT : this.getAvailableWrapT());

        _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, convertToPOT ? this.magFilter : this.getAvailableMagFilter());
        _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, convertToPOT ? this.minFilter : this.getAvailableMinFilter());

        var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic');
        if (anisotropicExt && this.anisotropic > 1) {
            _gl.texParameterf(_gl.TEXTURE_2D, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic);
        }

        // Fallback to float type if browser don't have half float extension
        if (glType === 36193) {
            var halfFloatExt = renderer.getGLExtension('OES_texture_half_float');
            if (!halfFloatExt) {
                glType = glenum.FLOAT;
            }
        }

        if (this.mipmaps.length) {
            var width = this.width;
            var height = this.height;
            for (var i = 0; i < this.mipmaps.length; i++) {
                var mipmap = this.mipmaps[i];
                this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType, false);
                width /= 2;
                height /= 2;
            }
        }
        else {
            this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType, convertToPOT);

            if (this.useMipmap && (!this.NPOT || convertToPOT)) {
                _gl.generateMipmap(_gl.TEXTURE_2D);
            }
        }

        _gl.bindTexture(_gl.TEXTURE_2D, null);
    },

    _updateTextureData: function (_gl, data, level, width, height, glFormat, glType, convertToPOT) {
        if (data.image) {
            var imgData = data.image;
            if (convertToPOT) {
                this._potCanvas = convertTextureToPowerOfTwo(this, this._potCanvas);
                imgData = this._potCanvas;
            }
            _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, glFormat, glType, imgData);
        }
        else {
            // Can be used as a blank texture when writing render to texture(RTT)
            if (
                glFormat <= src_Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT
                && glFormat >= src_Texture.COMPRESSED_RGB_S3TC_DXT1_EXT
            ) {
                _gl.compressedTexImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, data.pixels);
            }
            else {
                // Is a render target if pixels is null
                _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, glFormat, glType, data.pixels);
            }
        }
    },

    /**
     * @param  {clay.Renderer} renderer
     * @memberOf clay.Texture2D.prototype
     */
    generateMipmap: function (renderer) {
        var _gl = renderer.gl;
        if (this.useMipmap && !this.NPOT) {
            _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture'));
            _gl.generateMipmap(_gl.TEXTURE_2D);
        }
    },

    isPowerOfTwo: function () {
        return isPowerOfTwo(this.width) && isPowerOfTwo(this.height);
    },

    isRenderable: function () {
        if (this.image) {
            return this.image.width > 0 && this.image.height > 0;
        }
        else {
            return !!(this.width && this.height);
        }
    },

    bind: function (renderer) {
        renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.getWebGLTexture(renderer));
    },

    unbind: function (renderer) {
        renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, null);
    },

    load: function (src, crossOrigin) {
        var image = core_vendor.createImage();
        if (crossOrigin) {
            image.crossOrigin = crossOrigin;
        }
        var self = this;
        image.onload = function () {
            self.dirty();
            self.trigger('success', self);
        };
        image.onerror = function () {
            self.trigger('error', self);
        };

        image.src = src;
        this.image = image;

        return this;
    }
});

Object.defineProperty(Texture2D.prototype, 'width', {
    get: function () {
        if (this.image) {
            return this.image.width;
        }
        return this._width;
    },
    set: function (value) {
        if (this.image) {
            console.warn('Texture from image can\'t set width');
        }
        else {
            if (this._width !== value) {
                this.dirty();
            }
            this._width = value;
        }
    }
});
Object.defineProperty(Texture2D.prototype, 'height', {
    get: function () {
        if (this.image) {
            return this.image.height;
        }
        return this._height;
    },
    set: function (value) {
        if (this.image) {
            console.warn('Texture from image can\'t set height');
        }
        else {
            if (this._height !== value) {
                this.dirty();
            }
            this._height = value;
        }
    }
});

/* harmony default export */ const src_Texture2D = (Texture2D);

;// CONCATENATED MODULE: ./node_modules/claygl/src/GeometryBase.js





function getArrayCtorByType (type) {
    return ({
        'byte': core_vendor.Int8Array,
        'ubyte': core_vendor.Uint8Array,
        'short': core_vendor.Int16Array,
        'ushort': core_vendor.Uint16Array
    })[type] || core_vendor.Float32Array;
}

function makeAttrKey(attrName) {
    return 'attr_' + attrName;
}
/**
 * GeometryBase attribute
 * @alias clay.GeometryBase.Attribute
 * @constructor
 */
function Attribute(name, type, size, semantic) {
    /**
     * Attribute name
     * @type {string}
     */
    this.name = name;
    /**
     * Attribute type
     * Possible values:
     *  + `'byte'`
     *  + `'ubyte'`
     *  + `'short'`
     *  + `'ushort'`
     *  + `'float'` Most commonly used.
     * @type {string}
     */
    this.type = type;
    /**
     * Size of attribute component. 1 - 4.
     * @type {number}
     */
    this.size = size;
    /**
     * Semantic of this attribute.
     * Possible values:
     *  + `'POSITION'`
     *  + `'NORMAL'`
     *  + `'BINORMAL'`
     *  + `'TANGENT'`
     *  + `'TEXCOORD'`
     *  + `'TEXCOORD_0'`
     *  + `'TEXCOORD_1'`
     *  + `'COLOR'`
     *  + `'JOINT'`
     *  + `'WEIGHT'`
     *
     * In shader, attribute with same semantic will be automatically mapped. For example:
     * ```glsl
     * attribute vec3 pos: POSITION
     * ```
     * will use the attribute value with semantic POSITION in geometry, no matter what name it used.
     * @type {string}
     */
    this.semantic = semantic || '';

    /**
     * Value of the attribute.
     * @type {TypedArray}
     */
    this.value = null;

    // Init getter setter
    switch (size) {
        case 1:
            this.get = function (idx) {
                return this.value[idx];
            };
            this.set = function (idx, value) {
                this.value[idx] = value;
            };
            // Copy from source to target
            this.copy = function (target, source) {
                this.value[target] = this.value[target];
            };
            break;
        case 2:
            this.get = function (idx, out) {
                var arr = this.value;
                out[0] = arr[idx * 2];
                out[1] = arr[idx * 2 + 1];
                return out;
            };
            this.set = function (idx, val) {
                var arr = this.value;
                arr[idx * 2] = val[0];
                arr[idx * 2 + 1] = val[1];
            };
            this.copy = function (target, source) {
                var arr = this.value;
                source *= 2;
                target *= 2;
                arr[target] = arr[source];
                arr[target + 1] = arr[source + 1];
            };
            break;
        case 3:
            this.get = function (idx, out) {
                var idx3 = idx * 3;
                var arr = this.value;
                out[0] = arr[idx3];
                out[1] = arr[idx3 + 1];
                out[2] = arr[idx3 + 2];
                return out;
            };
            this.set = function (idx, val) {
                var idx3 = idx * 3;
                var arr = this.value;
                arr[idx3] = val[0];
                arr[idx3 + 1] = val[1];
                arr[idx3 + 2] = val[2];
            };
            this.copy = function (target, source) {
                var arr = this.value;
                source *= 3;
                target *= 3;
                arr[target] = arr[source];
                arr[target + 1] = arr[source + 1];
                arr[target + 2] = arr[source + 2];
            };
            break;
        case 4:
            this.get = function (idx, out) {
                var arr = this.value;
                var idx4 = idx * 4;
                out[0] = arr[idx4];
                out[1] = arr[idx4 + 1];
                out[2] = arr[idx4 + 2];
                out[3] = arr[idx4 + 3];
                return out;
            };
            this.set = function (idx, val) {
                var arr = this.value;
                var idx4 = idx * 4;
                arr[idx4] = val[0];
                arr[idx4 + 1] = val[1];
                arr[idx4 + 2] = val[2];
                arr[idx4 + 3] = val[3];
            };
            this.copy = function (target, source) {
                var arr = this.value;
                source *= 4;
                target *= 4;
                // copyWithin is extremely slow
                arr[target] = arr[source];
                arr[target + 1] = arr[source + 1];
                arr[target + 2] = arr[source + 2];
                arr[target + 3] = arr[source + 3];
            };
    }
}

/**
 * Set item value at give index. Second parameter val is number if size is 1
 * @function
 * @name clay.GeometryBase.Attribute#set
 * @param {number} idx
 * @param {number[]|number} val
 * @example
 * geometry.getAttribute('position').set(0, [1, 1, 1]);
 */

/**
 * Get item value at give index. Second parameter out is no need if size is 1
 * @function
 * @name clay.GeometryBase.Attribute#set
 * @param {number} idx
 * @param {number[]} [out]
 * @example
 * geometry.getAttribute('position').get(0, out);
 */

/**
 * Initialize attribute with given vertex count
 * @param {number} nVertex
 */
Attribute.prototype.init = function (nVertex) {
    if (!this.value || this.value.length !== nVertex * this.size) {
        var ArrayConstructor = getArrayCtorByType(this.type);
        this.value = new ArrayConstructor(nVertex * this.size);
    }
};

/**
 * Initialize attribute with given array. Which can be 1 dimensional or 2 dimensional
 * @param {Array} array
 * @example
 *  geometry.getAttribute('position').fromArray(
 *      [-1, 0, 0, 1, 0, 0, 0, 1, 0]
 *  );
 *  geometry.getAttribute('position').fromArray(
 *      [ [-1, 0, 0], [1, 0, 0], [0, 1, 0] ]
 *  );
 */
Attribute.prototype.fromArray = function (array) {
    var ArrayConstructor = getArrayCtorByType(this.type);
    var value;
    // Convert 2d array to flat
    if (array[0] && (array[0].length)) {
        var n = 0;
        var size = this.size;
        value = new ArrayConstructor(array.length * size);
        for (var i = 0; i < array.length; i++) {
            for (var j = 0; j < size; j++) {
                value[n++] = array[i][j];
            }
        }
    }
    else {
        value = new ArrayConstructor(array);
    }
    this.value = value;
};

Attribute.prototype.clone = function(copyValue) {
    var ret = new Attribute(this.name, this.type, this.size, this.semantic);
    // FIXME
    if (copyValue) {
        console.warn('todo');
    }
    return ret;
};

function AttributeBuffer(name, type, buffer, size, semantic) {
    this.name = name;
    this.type = type;
    this.buffer = buffer;
    this.size = size;
    this.semantic = semantic;

    // To be set in mesh
    // symbol in the shader
    this.symbol = '';

    // Needs remove flag
    this.needsRemove = false;
}

function IndicesBuffer(buffer) {
    this.buffer = buffer;
    this.count = 0;
}

/**
 * Base of all geometry. Use {@link clay.Geometry} for common 3D usage.
 * @constructor clay.GeometryBase
 * @extends clay.core.Base
 */
var GeometryBase = core_Base.extend(function () {
    return /** @lends clay.GeometryBase# */ {
        /**
         * Attributes of geometry.
         * @type {Object.<string, clay.GeometryBase.Attribute>}
         */
        attributes: {},

        /**
         * Indices of geometry.
         * @type {Uint16Array|Uint32Array}
         */
        indices: null,

        /**
         * Is vertices data dynamically updated.
         * Attributes value can't be changed after first render if dyanmic is false.
         * @type {boolean}
         */
        dynamic: true,

        _enabledAttributes: null,

        // PENDING
        // Init it here to avoid deoptimization when it's assigned in application dynamically
        __used: 0
    };
}, function () {
    // Use cache
    this._cache = new core_Cache();

    this._attributeList = Object.keys(this.attributes);

    this.__vaoCache = {};
},
/** @lends clay.GeometryBase.prototype */
{
    /**
     * Main attribute will be used to count vertex number
     * @type {string}
     */
    mainAttribute: '',
    /**
     * User defined picking algorithm instead of default
     * triangle ray intersection
     * x, y are NDC.
     * ```typescript
     * (x, y, renderer, camera, renderable, out) => boolean
     * ```
     * @type {?Function}
     */
    pick: null,

    /**
     * User defined ray picking algorithm instead of default
     * triangle ray intersection
     * ```typescript
     * (ray: clay.Ray, renderable: clay.Renderable, out: Array) => boolean
     * ```
     * @type {?Function}
     */
    pickByRay: null,

    /**
     * Mark attributes and indices in geometry needs to update.
     * Usually called after you change the data in attributes.
     */
    dirty: function () {
        var enabledAttributes = this.getEnabledAttributes();
        for (var i = 0; i < enabledAttributes.length; i++) {
            this.dirtyAttribute(enabledAttributes[i]);
        }
        this.dirtyIndices();
        this._enabledAttributes = null;

        this._cache.dirty('any');
    },
    /**
     * Mark the indices needs to update.
     */
    dirtyIndices: function () {
        this._cache.dirtyAll('indices');
    },
    /**
     * Mark the attributes needs to update.
     * @param {string} [attrName]
     */
    dirtyAttribute: function (attrName) {
        this._cache.dirtyAll(makeAttrKey(attrName));
        this._cache.dirtyAll('attributes');
    },
    /**
     * Get indices of triangle at given index.
     * @param {number} idx
     * @param {Array.<number>} out
     * @return {Array.<number>}
     */
    getTriangleIndices: function (idx, out) {
        if (idx < this.triangleCount && idx >= 0) {
            if (!out) {
                out = [];
            }
            var indices = this.indices;
            out[0] = indices[idx * 3];
            out[1] = indices[idx * 3 + 1];
            out[2] = indices[idx * 3 + 2];
            return out;
        }
    },

    /**
     * Set indices of triangle at given index.
     * @param {number} idx
     * @param {Array.<number>} arr
     */
    setTriangleIndices: function (idx, arr) {
        var indices = this.indices;
        indices[idx * 3] = arr[0];
        indices[idx * 3 + 1] = arr[1];
        indices[idx * 3 + 2] = arr[2];
    },

    isUseIndices: function () {
        return !!this.indices;
    },

    /**
     * Initialize indices from an array.
     * @param {Array} array
     */
    initIndicesFromArray: function (array) {
        var value;
        var ArrayConstructor = this.vertexCount > 0xffff
            ? core_vendor.Uint32Array : core_vendor.Uint16Array;
        // Convert 2d array to flat
        if (array[0] && (array[0].length)) {
            var n = 0;
            var size = 3;

            value = new ArrayConstructor(array.length * size);
            for (var i = 0; i < array.length; i++) {
                for (var j = 0; j < size; j++) {
                    value[n++] = array[i][j];
                }
            }
        }
        else {
            value = new ArrayConstructor(array);
        }

        this.indices = value;
    },
    /**
     * Create a new attribute
     * @param {string} name
     * @param {string} type
     * @param {number} size
     * @param {string} [semantic]
     */
    createAttribute: function (name, type, size, semantic) {
        var attrib = new Attribute(name, type, size, semantic);
        if (this.attributes[name]) {
            this.removeAttribute(name);
        }
        this.attributes[name] = attrib;
        this._attributeList.push(name);
        return attrib;
    },
    /**
     * Remove attribute
     * @param {string} name
     */
    removeAttribute: function (name) {
        var attributeList = this._attributeList;
        var idx = attributeList.indexOf(name);
        if (idx >= 0) {
            attributeList.splice(idx, 1);
            delete this.attributes[name];
            return true;
        }
        return false;
    },

    /**
     * Get attribute
     * @param {string} name
     * @return {clay.GeometryBase.Attribute}
     */
    getAttribute: function (name) {
        return this.attributes[name];
    },

    /**
     * Get enabled attributes name list
     * Attribute which has the same vertex number with position is treated as a enabled attribute
     * @return {string[]}
     */
    getEnabledAttributes: function () {
        var enabledAttributes = this._enabledAttributes;
        var attributeList = this._attributeList;
        // Cache
        if (enabledAttributes) {
            return enabledAttributes;
        }

        var result = [];
        var nVertex = this.vertexCount;

        for (var i = 0; i < attributeList.length; i++) {
            var name = attributeList[i];
            var attrib = this.attributes[name];
            if (attrib.value) {
                if (attrib.value.length === nVertex * attrib.size) {
                    result.push(name);
                }
            }
        }

        this._enabledAttributes = result;

        return result;
    },

    getBufferChunks: function (renderer) {
        var cache = this._cache;
        cache.use(renderer.__uid__);
        var isAttributesDirty = cache.isDirty('attributes');
        var isIndicesDirty = cache.isDirty('indices');
        if (isAttributesDirty || isIndicesDirty) {
            this._updateBuffer(renderer.gl, isAttributesDirty, isIndicesDirty);
            var enabledAttributes = this.getEnabledAttributes();
            for (var i = 0; i < enabledAttributes.length; i++) {
                cache.fresh(makeAttrKey(enabledAttributes[i]));
            }
            cache.fresh('attributes');
            cache.fresh('indices');
        }
        cache.fresh('any');
        return cache.get('chunks');
    },

    _updateBuffer: function (_gl, isAttributesDirty, isIndicesDirty) {
        var cache = this._cache;
        var chunks = cache.get('chunks');
        var firstUpdate = false;
        if (!chunks) {
            chunks = [];
            // Intialize
            chunks[0] = {
                attributeBuffers: [],
                indicesBuffer: null
            };
            cache.put('chunks', chunks);
            firstUpdate = true;
        }

        var chunk = chunks[0];
        var attributeBuffers = chunk.attributeBuffers;
        var indicesBuffer = chunk.indicesBuffer;

        if (isAttributesDirty || firstUpdate) {
            var attributeList = this.getEnabledAttributes();

            var attributeBufferMap = {};
            if (!firstUpdate) {
                for (var i = 0; i < attributeBuffers.length; i++) {
                    attributeBufferMap[attributeBuffers[i].name] = attributeBuffers[i];
                }
            }
            // FIXME If some attributes removed
            for (var k = 0; k < attributeList.length; k++) {
                var name = attributeList[k];
                var attribute = this.attributes[name];

                var bufferInfo;

                if (!firstUpdate) {
                    bufferInfo = attributeBufferMap[name];
                }
                var buffer;
                if (bufferInfo) {
                    buffer = bufferInfo.buffer;
                }
                else {
                    buffer = _gl.createBuffer();
                }
                if (cache.isDirty(makeAttrKey(name))) {
                    // Only update when they are dirty.
                    // TODO: Use BufferSubData?
                    _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer);
                    _gl.bufferData(_gl.ARRAY_BUFFER, attribute.value, this.dynamic ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW);
                }

                attributeBuffers[k] = new AttributeBuffer(name, attribute.type, buffer, attribute.size, attribute.semantic);
            }
            // Remove unused attributes buffers.
            // PENDING
            for (var i = k; i < attributeBuffers.length; i++) {
                _gl.deleteBuffer(attributeBuffers[i].buffer);
            }
            attributeBuffers.length = k;

        }

        if (this.isUseIndices() && (isIndicesDirty || firstUpdate)) {
            if (!indicesBuffer) {
                indicesBuffer = new IndicesBuffer(_gl.createBuffer());
                chunk.indicesBuffer = indicesBuffer;
            }
            indicesBuffer.count = this.indices.length;
            _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer);
            _gl.bufferData(_gl.ELEMENT_ARRAY_BUFFER, this.indices, this.dynamic ? _gl.DYNAMIC_DRAW : _gl.STATIC_DRAW);
        }
    },

    /**
     * Dispose geometry data in GL context.
     * @param {clay.Renderer} renderer
     */
    dispose: function (renderer) {

        var cache = this._cache;

        cache.use(renderer.__uid__);
        var chunks = cache.get('chunks');
        if (chunks) {
            for (var c = 0; c < chunks.length; c++) {
                var chunk = chunks[c];

                for (var k = 0; k < chunk.attributeBuffers.length; k++) {
                    var attribs = chunk.attributeBuffers[k];
                    renderer.gl.deleteBuffer(attribs.buffer);
                }

                if (chunk.indicesBuffer) {
                    renderer.gl.deleteBuffer(chunk.indicesBuffer.buffer);
                }
            }
        }
        if (this.__vaoCache) {
            var vaoExt = renderer.getGLExtension('OES_vertex_array_object');
            for (var id in this.__vaoCache) {
                var vao = this.__vaoCache[id].vao;
                if (vao) {
                    vaoExt.deleteVertexArrayOES(vao);
                }
            }
        }
        this.__vaoCache = {};
        cache.deleteContext(renderer.__uid__);
    }

});

if (Object.defineProperty) {
    /**
     * @name clay.GeometryBase#vertexCount
     * @type {number}
     * @readOnly
     */
    Object.defineProperty(GeometryBase.prototype, 'vertexCount', {

        enumerable: false,

        get: function () {

            var mainAttribute = this.attributes[this.mainAttribute];

            if (!mainAttribute) {
                mainAttribute = this.attributes[this._attributeList[0]];
            }

            if (!mainAttribute || !mainAttribute.value) {
                return 0;
            }
            return mainAttribute.value.length / mainAttribute.size;
        }
    });
    /**
     * @name clay.GeometryBase#triangleCount
     * @type {number}
     * @readOnly
     */
    Object.defineProperty(GeometryBase.prototype, 'triangleCount', {

        enumerable: false,

        get: function () {
            var indices = this.indices;
            if (!indices) {
                return 0;
            }
            else {
                return indices.length / 3;
            }
        }
    });
}

GeometryBase.STATIC_DRAW = glenum.STATIC_DRAW;
GeometryBase.DYNAMIC_DRAW = glenum.DYNAMIC_DRAW;
GeometryBase.STREAM_DRAW = glenum.STREAM_DRAW;

GeometryBase.AttributeBuffer = AttributeBuffer;
GeometryBase.IndicesBuffer = IndicesBuffer;

GeometryBase.Attribute = Attribute;

/* harmony default export */ const src_GeometryBase = (GeometryBase);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Geometry.js






var vec3Create = glmatrix_vec3.create;
var vec3Add = glmatrix_vec3.add;
var Geometry_vec3Set = glmatrix_vec3.set;

var Geometry_Attribute = src_GeometryBase.Attribute;

/**
 * Geometry in ClayGL contains vertex attributes of mesh. These vertex attributes will be finally provided to the {@link clay.Shader}.
 * Different {@link clay.Shader} needs different attributes. Here is a list of attributes used in the builtin shaders.
 *
 * + position: `clay.basic`, `clay.lambert`, `clay.standard`
 * + texcoord0: `clay.basic`, `clay.lambert`, `clay.standard`
 * + color: `clay.basic`, `clay.lambert`, `clay.standard`
 * + weight: `clay.basic`, `clay.lambert`, `clay.standard`
 * + joint: `clay.basic`, `clay.lambert`, `clay.standard`
 * + normal: `clay.lambert`, `clay.standard`
 * + tangent: `clay.standard`
 *
 * #### Create a procedural geometry
 *
 * ClayGL provides a couple of builtin procedural geometries. Inlcuding:
 *
 *  + {@link clay.geometry.Cube}
 *  + {@link clay.geometry.Sphere}
 *  + {@link clay.geometry.Plane}
 *  + {@link clay.geometry.Cylinder}
 *  + {@link clay.geometry.Cone}
 *  + {@link clay.geometry.ParametricSurface}
 *
 * It's simple to create a basic geometry with these classes.
 *
```js
var sphere = new clay.geometry.Sphere({
    radius: 2
});
```
 *
 * #### Create the geometry data by yourself
 *
 * Usually the vertex attributes data are created by the {@link clay.loader.GLTF} or procedural geometries like {@link clay.geometry.Sphere}.
 * Besides these, you can create the data manually. Here is a simple example to create a triangle.
```js
var TRIANGLE_POSITIONS = [
    [-0.5, -0.5, 0],
    [0.5, -0.5, 0],
    [0, 0.5, 0]
];
var geometry = new clay.StaticGeometryBase();
// Add triangle vertices to position attribute.
geometry.attributes.position.fromArray(TRIANGLE_POSITIONS);
```
 * Then you can use the utility methods like `generateVertexNormals`, `generateTangents` to create the remaining necessary attributes.
 *
 *
 * #### Use with custom shaders
 *
 * If you wan't to write custom shaders. Don't forget to add SEMANTICS to these attributes. For example
 *
 ```glsl
uniform mat4 worldViewProjection : WORLDVIEWPROJECTION;
uniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;
uniform mat4 world : WORLD;

attribute vec3 position : POSITION;
attribute vec2 texcoord : TEXCOORD_0;
attribute vec3 normal : NORMAL;
```
 * These `POSITION`, `TEXCOORD_0`, `NORMAL` are SEMANTICS which will map the attributes in shader to the attributes in the GeometryBase
 *
 * Available attributes SEMANTICS includes `POSITION`, `TEXCOORD_0`, `TEXCOORD_1` `NORMAL`, `TANGENT`, `COLOR`, `WEIGHT`, `JOINT`.
 *
 *
 * @constructor clay.Geometry
 * @extends clay.GeometryBase
 */
var Geometry = src_GeometryBase.extend(function () {
    return /** @lends clay.Geometry# */ {
        /**
         * Attributes of geometry. Including:
         *  + `position`
         *  + `texcoord0`
         *  + `texcoord1`
         *  + `normal`
         *  + `tangent`
         *  + `color`
         *  + `weight`
         *  + `joint`
         *  + `barycentric`
         *
         * @type {Object.<string, clay.Geometry.Attribute>}
         */
        attributes: {
            position: new Geometry_Attribute('position', 'float', 3, 'POSITION'),
            texcoord0: new Geometry_Attribute('texcoord0', 'float', 2, 'TEXCOORD_0'),
            texcoord1: new Geometry_Attribute('texcoord1', 'float', 2, 'TEXCOORD_1'),
            normal: new Geometry_Attribute('normal', 'float', 3, 'NORMAL'),
            tangent: new Geometry_Attribute('tangent', 'float', 4, 'TANGENT'),
            color: new Geometry_Attribute('color', 'float', 4, 'COLOR'),
            // Skinning attributes
            // Each vertex can be bind to 4 bones, because the
            // sum of weights is 1, so the weights is stored in vec3 and the last
            // can be calculated by 1-w.x-w.y-w.z
            weight: new Geometry_Attribute('weight', 'float', 3, 'WEIGHT'),
            joint: new Geometry_Attribute('joint', 'float', 4, 'JOINT'),
            // For wireframe display
            // http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/
            barycentric: new Geometry_Attribute('barycentric', 'float', 3, null),
        },
        /**
         * Calculated bounding box of geometry.
         * @type {clay.BoundingBox}
         */
        boundingBox: null
    };
},
/** @lends clay.Geometry.prototype */
{

    mainAttribute: 'position',

    /**
     * Update boundingBox of Geometry
     */
    updateBoundingBox: function () {
        var bbox = this.boundingBox;
        if (!bbox) {
            bbox = this.boundingBox = new math_BoundingBox();
        }
        var posArr = this.attributes.position.value;
        if (posArr && posArr.length) {
            var min = bbox.min;
            var max = bbox.max;
            var minArr = min.array;
            var maxArr = max.array;
            glmatrix_vec3.set(minArr, posArr[0], posArr[1], posArr[2]);
            glmatrix_vec3.set(maxArr, posArr[0], posArr[1], posArr[2]);
            for (var i = 3; i < posArr.length;) {
                var x = posArr[i++];
                var y = posArr[i++];
                var z = posArr[i++];
                if (x < minArr[0]) { minArr[0] = x; }
                if (y < minArr[1]) { minArr[1] = y; }
                if (z < minArr[2]) { minArr[2] = z; }

                if (x > maxArr[0]) { maxArr[0] = x; }
                if (y > maxArr[1]) { maxArr[1] = y; }
                if (z > maxArr[2]) { maxArr[2] = z; }
            }
            min._dirty = true;
            max._dirty = true;
        }
    },

    /**
     * Generate normals per vertex.
     */
    generateVertexNormals: function () {
        if (!this.vertexCount) {
            return;
        }

        var indices = this.indices;
        var attributes = this.attributes;
        var positions = attributes.position.value;
        var normals = attributes.normal.value;

        if (!normals || normals.length !== positions.length) {
            normals = attributes.normal.value = new core_vendor.Float32Array(positions.length);
        }
        else {
            // Reset
            for (var i = 0; i < normals.length; i++) {
                normals[i] = 0;
            }
        }

        var p1 = vec3Create();
        var p2 = vec3Create();
        var p3 = vec3Create();

        var v21 = vec3Create();
        var v32 = vec3Create();

        var n = vec3Create();

        var len = indices ? indices.length : this.vertexCount;
        var i1, i2, i3;
        for (var f = 0; f < len;) {
            if (indices) {
                i1 = indices[f++];
                i2 = indices[f++];
                i3 = indices[f++];
            }
            else {
                i1 = f++;
                i2 = f++;
                i3 = f++;
            }

            Geometry_vec3Set(p1, positions[i1*3], positions[i1*3+1], positions[i1*3+2]);
            Geometry_vec3Set(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]);
            Geometry_vec3Set(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]);

            glmatrix_vec3.sub(v21, p1, p2);
            glmatrix_vec3.sub(v32, p2, p3);
            glmatrix_vec3.cross(n, v21, v32);
            // Already be weighted by the triangle area
            for (var i = 0; i < 3; i++) {
                normals[i1*3+i] = normals[i1*3+i] + n[i];
                normals[i2*3+i] = normals[i2*3+i] + n[i];
                normals[i3*3+i] = normals[i3*3+i] + n[i];
            }
        }

        for (var i = 0; i < normals.length;) {
            Geometry_vec3Set(n, normals[i], normals[i+1], normals[i+2]);
            glmatrix_vec3.normalize(n, n);
            normals[i++] = n[0];
            normals[i++] = n[1];
            normals[i++] = n[2];
        }
        this.dirty();
    },

    /**
     * Generate normals per face.
     */
    generateFaceNormals: function () {
        if (!this.vertexCount) {
            return;
        }

        if (!this.isUniqueVertex()) {
            this.generateUniqueVertex();
        }

        var indices = this.indices;
        var attributes = this.attributes;
        var positions = attributes.position.value;
        var normals = attributes.normal.value;

        var p1 = vec3Create();
        var p2 = vec3Create();
        var p3 = vec3Create();

        var v21 = vec3Create();
        var v32 = vec3Create();
        var n = vec3Create();

        if (!normals) {
            normals = attributes.normal.value = new Float32Array(positions.length);
        }
        var len = indices ? indices.length : this.vertexCount;
        var i1, i2, i3;
        for (var f = 0; f < len;) {
            if (indices) {
                i1 = indices[f++];
                i2 = indices[f++];
                i3 = indices[f++];
            }
            else {
                i1 = f++;
                i2 = f++;
                i3 = f++;
            }

            Geometry_vec3Set(p1, positions[i1*3], positions[i1*3+1], positions[i1*3+2]);
            Geometry_vec3Set(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]);
            Geometry_vec3Set(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]);

            glmatrix_vec3.sub(v21, p1, p2);
            glmatrix_vec3.sub(v32, p2, p3);
            glmatrix_vec3.cross(n, v21, v32);

            glmatrix_vec3.normalize(n, n);

            for (var i = 0; i < 3; i++) {
                normals[i1*3 + i] = n[i];
                normals[i2*3 + i] = n[i];
                normals[i3*3 + i] = n[i];
            }
        }
        this.dirty();
    },

    /**
     * Generate tangents attributes.
     */
    generateTangents: function () {
        if (!this.vertexCount) {
            return;
        }

        var nVertex = this.vertexCount;
        var attributes = this.attributes;
        if (!attributes.tangent.value) {
            attributes.tangent.value = new Float32Array(nVertex * 4);
        }
        var texcoords = attributes.texcoord0.value;
        var positions = attributes.position.value;
        var tangents = attributes.tangent.value;
        var normals = attributes.normal.value;

        if (!texcoords) {
            console.warn('Geometry without texcoords can\'t generate tangents.');
            return;
        }

        var tan1 = [];
        var tan2 = [];
        for (var i = 0; i < nVertex; i++) {
            tan1[i] = [0.0, 0.0, 0.0];
            tan2[i] = [0.0, 0.0, 0.0];
        }

        var sdir = [0.0, 0.0, 0.0];
        var tdir = [0.0, 0.0, 0.0];
        var indices = this.indices;

        var len = indices ? indices.length : this.vertexCount;
        var i1, i2, i3;
        for (var i = 0; i < len;) {
            if (indices) {
                i1 = indices[i++];
                i2 = indices[i++];
                i3 = indices[i++];
            }
            else {
                i1 = i++;
                i2 = i++;
                i3 = i++;
            }

            var st1s = texcoords[i1 * 2],
                st2s = texcoords[i2 * 2],
                st3s = texcoords[i3 * 2],
                st1t = texcoords[i1 * 2 + 1],
                st2t = texcoords[i2 * 2 + 1],
                st3t = texcoords[i3 * 2 + 1],

                p1x = positions[i1 * 3],
                p2x = positions[i2 * 3],
                p3x = positions[i3 * 3],
                p1y = positions[i1 * 3 + 1],
                p2y = positions[i2 * 3 + 1],
                p3y = positions[i3 * 3 + 1],
                p1z = positions[i1 * 3 + 2],
                p2z = positions[i2 * 3 + 2],
                p3z = positions[i3 * 3 + 2];

            var x1 = p2x - p1x,
                x2 = p3x - p1x,
                y1 = p2y - p1y,
                y2 = p3y - p1y,
                z1 = p2z - p1z,
                z2 = p3z - p1z;

            var s1 = st2s - st1s,
                s2 = st3s - st1s,
                t1 = st2t - st1t,
                t2 = st3t - st1t;

            var r = 1.0 / (s1 * t2 - t1 * s2);
            sdir[0] = (t2 * x1 - t1 * x2) * r;
            sdir[1] = (t2 * y1 - t1 * y2) * r;
            sdir[2] = (t2 * z1 - t1 * z2) * r;

            tdir[0] = (s1 * x2 - s2 * x1) * r;
            tdir[1] = (s1 * y2 - s2 * y1) * r;
            tdir[2] = (s1 * z2 - s2 * z1) * r;

            vec3Add(tan1[i1], tan1[i1], sdir);
            vec3Add(tan1[i2], tan1[i2], sdir);
            vec3Add(tan1[i3], tan1[i3], sdir);
            vec3Add(tan2[i1], tan2[i1], tdir);
            vec3Add(tan2[i2], tan2[i2], tdir);
            vec3Add(tan2[i3], tan2[i3], tdir);
        }
        var tmp = vec3Create();
        var nCrossT = vec3Create();
        var n = vec3Create();
        for (var i = 0; i < nVertex; i++) {
            n[0] = normals[i * 3];
            n[1] = normals[i * 3 + 1];
            n[2] = normals[i * 3 + 2];
            var t = tan1[i];

            // Gram-Schmidt orthogonalize
            glmatrix_vec3.scale(tmp, n, glmatrix_vec3.dot(n, t));
            glmatrix_vec3.sub(tmp, t, tmp);
            glmatrix_vec3.normalize(tmp, tmp);
            // Calculate handedness.
            glmatrix_vec3.cross(nCrossT, n, t);
            tangents[i * 4] = tmp[0];
            tangents[i * 4 + 1] = tmp[1];
            tangents[i * 4 + 2] = tmp[2];
            // PENDING can config ?
            tangents[i * 4 + 3] = glmatrix_vec3.dot(nCrossT, tan2[i]) < 0.0 ? -1.0 : 1.0;
        }
        this.dirty();
    },

    /**
     * If vertices are not shared by different indices.
     */
    isUniqueVertex: function () {
        if (this.isUseIndices()) {
            return this.vertexCount === this.indices.length;
        }
        else {
            return true;
        }
    },
    /**
     * Create a unique vertex for each index.
     */
    generateUniqueVertex: function () {
        if (!this.vertexCount || !this.indices) {
            return;
        }

        if (this.indices.length > 0xffff) {
            this.indices = new core_vendor.Uint32Array(this.indices);
        }

        var attributes = this.attributes;
        var indices = this.indices;

        var attributeNameList = this.getEnabledAttributes();

        var oldAttrValues = {};
        for (var a = 0; a < attributeNameList.length; a++) {
            var name = attributeNameList[a];
            oldAttrValues[name] = attributes[name].value;
            attributes[name].init(this.indices.length);
        }

        var cursor = 0;
        for (var i = 0; i < indices.length; i++) {
            var ii = indices[i];
            for (var a = 0; a < attributeNameList.length; a++) {
                var name = attributeNameList[a];
                var array = attributes[name].value;
                var size = attributes[name].size;

                for (var k = 0; k < size; k++) {
                    array[cursor * size + k] = oldAttrValues[name][ii * size + k];
                }
            }
            indices[i] = cursor;
            cursor++;
        }

        this.dirty();
    },

    /**
     * Generate barycentric coordinates for wireframe draw.
     */
    generateBarycentric: function () {
        if (!this.vertexCount) {
            return;
        }

        if (!this.isUniqueVertex()) {
            this.generateUniqueVertex();
        }

        var attributes = this.attributes;
        var array = attributes.barycentric.value;
        var indices = this.indices;
        // Already existed;
        if (array && array.length === indices.length * 3) {
            return;
        }
        array = attributes.barycentric.value = new Float32Array(indices.length * 3);

        for (var i = 0; i < (indices ? indices.length : this.vertexCount / 3);) {
            for (var j = 0; j < 3; j++) {
                var ii = indices ? indices[i++] : (i * 3 + j);
                array[ii * 3 + j] = 1;
            }
        }
        this.dirty();
    },

    /**
     * Apply transform to geometry attributes.
     * @param {clay.Matrix4} matrix
     */
    applyTransform: function (matrix) {

        var attributes = this.attributes;
        var positions = attributes.position.value;
        var normals = attributes.normal.value;
        var tangents = attributes.tangent.value;

        matrix = matrix.array;
        // Normal Matrix
        var inverseTransposeMatrix = glmatrix_mat4.create();
        glmatrix_mat4.invert(inverseTransposeMatrix, matrix);
        glmatrix_mat4.transpose(inverseTransposeMatrix, inverseTransposeMatrix);

        var vec3TransformMat4 = glmatrix_vec3.transformMat4;
        var vec3ForEach = glmatrix_vec3.forEach;
        vec3ForEach(positions, 3, 0, null, vec3TransformMat4, matrix);
        if (normals) {
            vec3ForEach(normals, 3, 0, null, vec3TransformMat4, inverseTransposeMatrix);
        }
        if (tangents) {
            vec3ForEach(tangents, 4, 0, null, vec3TransformMat4, inverseTransposeMatrix);
        }

        if (this.boundingBox) {
            this.updateBoundingBox();
        }
    },
    /**
     * Dispose geometry data in GL context.
     * @param {clay.Renderer} renderer
     */
    dispose: function (renderer) {

        var cache = this._cache;

        cache.use(renderer.__uid__);
        var chunks = cache.get('chunks');
        if (chunks) {
            for (var c = 0; c < chunks.length; c++) {
                var chunk = chunks[c];

                for (var k = 0; k < chunk.attributeBuffers.length; k++) {
                    var attribs = chunk.attributeBuffers[k];
                    renderer.gl.deleteBuffer(attribs.buffer);
                }

                if (chunk.indicesBuffer) {
                    renderer.gl.deleteBuffer(chunk.indicesBuffer.buffer);
                }
            }
        }
        if (this.__vaoCache) {
            var vaoExt = renderer.getGLExtension('OES_vertex_array_object');
            for (var id in this.__vaoCache) {
                var vao = this.__vaoCache[id].vao;
                if (vao) {
                    vaoExt.deleteVertexArrayOES(vao);
                }
            }
        }
        this.__vaoCache = {};
        cache.deleteContext(renderer.__uid__);
    }

});

Geometry.STATIC_DRAW = src_GeometryBase.STATIC_DRAW;
Geometry.DYNAMIC_DRAW = src_GeometryBase.DYNAMIC_DRAW;
Geometry.STREAM_DRAW = src_GeometryBase.STREAM_DRAW;

Geometry.AttributeBuffer = src_GeometryBase.AttributeBuffer;
Geometry.IndicesBuffer = src_GeometryBase.IndicesBuffer;

Geometry.Attribute = Geometry_Attribute;

/* harmony default export */ const src_Geometry = (Geometry);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/header/calcAmbientSHLight.glsl.js
/* harmony default export */ const calcAmbientSHLight_glsl = ("vec3 calcAmbientSHLight(int idx, vec3 N) {\n int offset = 9 * idx;\n return ambientSHLightCoefficients[0]\n + ambientSHLightCoefficients[1] * N.x\n + ambientSHLightCoefficients[2] * N.y\n + ambientSHLightCoefficients[3] * N.z\n + ambientSHLightCoefficients[4] * N.x * N.z\n + ambientSHLightCoefficients[5] * N.z * N.y\n + ambientSHLightCoefficients[6] * N.y * N.x\n + ambientSHLightCoefficients[7] * (3.0 * N.z * N.z - 1.0)\n + ambientSHLightCoefficients[8] * (N.x * N.x - N.y * N.y);\n}");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/header/light.js


var uniformVec3Prefix = 'uniform vec3 ';
var uniformFloatPrefix = 'uniform float ';
var exportHeaderPrefix = '@export clay.header.';
var exportEnd = '@end';
var unconfigurable = ':unconfigurable;';
/* harmony default export */ const light = ([
    exportHeaderPrefix + 'directional_light',
    uniformVec3Prefix + 'directionalLightDirection[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable,
    uniformVec3Prefix + 'directionalLightColor[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable,
    exportEnd,

    exportHeaderPrefix + 'ambient_light',
    uniformVec3Prefix + 'ambientLightColor[AMBIENT_LIGHT_COUNT]' + unconfigurable,
    exportEnd,

    exportHeaderPrefix + 'ambient_sh_light',
    uniformVec3Prefix + 'ambientSHLightColor[AMBIENT_SH_LIGHT_COUNT]' + unconfigurable,
    uniformVec3Prefix + 'ambientSHLightCoefficients[AMBIENT_SH_LIGHT_COUNT * 9]' + unconfigurable,
    calcAmbientSHLight_glsl,
    exportEnd,

    exportHeaderPrefix + 'ambient_cubemap_light',
    uniformVec3Prefix + 'ambientCubemapLightColor[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable,
    'uniform samplerCube ambientCubemapLightCubemap[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable,
    'uniform sampler2D ambientCubemapLightBRDFLookup[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable,
    exportEnd,

    exportHeaderPrefix + 'point_light',
    uniformVec3Prefix + 'pointLightPosition[POINT_LIGHT_COUNT]' + unconfigurable,
    uniformFloatPrefix + 'pointLightRange[POINT_LIGHT_COUNT]' + unconfigurable,
    uniformVec3Prefix + 'pointLightColor[POINT_LIGHT_COUNT]' + unconfigurable,
    exportEnd,

    exportHeaderPrefix + 'spot_light',
    uniformVec3Prefix + 'spotLightPosition[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformVec3Prefix + 'spotLightDirection[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformFloatPrefix + 'spotLightRange[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformFloatPrefix + 'spotLightUmbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformFloatPrefix + 'spotLightPenumbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformFloatPrefix + 'spotLightFalloffFactor[SPOT_LIGHT_COUNT]' + unconfigurable,
    uniformVec3Prefix + 'spotLightColor[SPOT_LIGHT_COUNT]' + unconfigurable,
    exportEnd
].join('\n'));

;// CONCATENATED MODULE: ./node_modules/claygl/src/Light.js




src_Shader.import(light);

/**
 * @constructor clay.Light
 * @extends clay.Node
 */
var Light = src_Node.extend(function(){
    return /** @lends clay.Light# */ {
        /**
         * Light RGB color
         * @type {number[]}
         */
        color: [1, 1, 1],

        /**
         * Light intensity
         * @type {number}
         */
        intensity: 1.0,

        // Config for shadow map
        /**
         * If light cast shadow
         * @type {boolean}
         */
        castShadow: true,

        /**
         * Shadow map size
         * @type {number}
         */
        shadowResolution: 512,

        /**
         * Light group, shader with same `lightGroup` will be affected
         *
         * Only useful in forward rendering
         * @type {number}
         */
        group: 0
    };
},
/** @lends clay.Light.prototype. */
{
    /**
     * Light type
     * @type {string}
     * @memberOf clay.Light#
     */
    type: '',

    /**
     * @return {clay.Light}
     * @memberOf clay.Light.prototype
     */
    clone: function() {
        var light = src_Node.prototype.clone.call(this);
        light.color = Array.prototype.slice.call(this.color);
        light.intensity = this.intensity;
        light.castShadow = this.castShadow;
        light.shadowResolution = this.shadowResolution;

        return light;
    }
});

/* harmony default export */ const src_Light = (Light);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Plane.js





/**
 * @constructor
 * @alias clay.Plane
 * @param {clay.Vector3} [normal]
 * @param {number} [distance]
 */
var Plane = function(normal, distance) {
    /**
     * Normal of the plane
     * @type {clay.Vector3}
     */
    this.normal = normal || new math_Vector3(0, 1, 0);

    /**
     * Constant of the plane equation, used as distance to the origin
     * @type {number}
     */
    this.distance = distance || 0;
};

Plane.prototype = {

    constructor: Plane,

    /**
     * Distance from a given point to the plane
     * @param  {clay.Vector3} point
     * @return {number}
     */
    distanceToPoint: function(point) {
        return glmatrix_vec3.dot(point.array, this.normal.array) - this.distance;
    },

    /**
     * Calculate the projection point on the plane
     * @param  {clay.Vector3} point
     * @param  {clay.Vector3} out
     * @return {clay.Vector3}
     */
    projectPoint: function(point, out) {
        if (!out) {
            out = new math_Vector3();
        }
        var d = this.distanceToPoint(point);
        glmatrix_vec3.scaleAndAdd(out.array, point.array, this.normal.array, -d);
        out._dirty = true;
        return out;
    },

    /**
     * Normalize the plane's normal and calculate the distance
     */
    normalize: function() {
        var invLen = 1 / glmatrix_vec3.len(this.normal.array);
        glmatrix_vec3.scale(this.normal.array, invLen);
        this.distance *= invLen;
    },

    /**
     * If the plane intersect a frustum
     * @param  {clay.Frustum} Frustum
     * @return {boolean}
     */
    intersectFrustum: function(frustum) {
        // Check if all coords of frustum is on plane all under plane
        var coords = frustum.vertices;
        var normal = this.normal.array;
        var onPlane = glmatrix_vec3.dot(coords[0].array, normal) > this.distance;
        for (var i = 1; i < 8; i++) {
            if ((glmatrix_vec3.dot(coords[i].array, normal) > this.distance) != onPlane) {
                return true;
            }
        }
    },

    /**
     * Calculate the intersection point between plane and a given line
     * @function
     * @param {clay.Vector3} start start point of line
     * @param {clay.Vector3} end end point of line
     * @param {clay.Vector3} [out]
     * @return {clay.Vector3}
     */
    intersectLine: (function() {
        var rd = glmatrix_vec3.create();
        return function(start, end, out) {
            var d0 = this.distanceToPoint(start);
            var d1 = this.distanceToPoint(end);
            if ((d0 > 0 && d1 > 0) || (d0 < 0 && d1 < 0)) {
                return null;
            }
            // Ray intersection
            var pn = this.normal.array;
            var d = this.distance;
            var ro = start.array;
            // direction
            glmatrix_vec3.sub(rd, end.array, start.array);
            glmatrix_vec3.normalize(rd, rd);

            var divider = glmatrix_vec3.dot(pn, rd);
            // ray is parallel to the plane
            if (divider === 0) {
                return null;
            }
            if (!out) {
                out = new math_Vector3();
            }
            var t = (glmatrix_vec3.dot(pn, ro) - d) / divider;
            glmatrix_vec3.scaleAndAdd(out.array, ro, rd, -t);
            out._dirty = true;
            return out;
        };
    })(),

    /**
     * Apply an affine transform matrix to plane
     * @function
     * @return {clay.Matrix4}
     */
    applyTransform: (function() {
        var inverseTranspose = glmatrix_mat4.create();
        var normalv4 = glmatrix_vec4.create();
        var pointv4 = glmatrix_vec4.create();
        pointv4[3] = 1;
        return function(m4) {
            m4 = m4.array;
            // Transform point on plane
            glmatrix_vec3.scale(pointv4, this.normal.array, this.distance);
            glmatrix_vec4.transformMat4(pointv4, pointv4, m4);
            this.distance = glmatrix_vec3.dot(pointv4, this.normal.array);
            // Transform plane normal
            glmatrix_mat4.invert(inverseTranspose, m4);
            glmatrix_mat4.transpose(inverseTranspose, inverseTranspose);
            normalv4[3] = 0;
            glmatrix_vec3.copy(normalv4, this.normal.array);
            glmatrix_vec4.transformMat4(normalv4, normalv4, inverseTranspose);
            glmatrix_vec3.copy(this.normal.array, normalv4);
        };
    })(),

    /**
     * Copy from another plane
     * @param  {clay.Vector3} plane
     */
    copy: function(plane) {
        glmatrix_vec3.copy(this.normal.array, plane.normal.array);
        this.normal._dirty = true;
        this.distance = plane.distance;
    },

    /**
     * Clone a new plane
     * @return {clay.Plane}
     */
    clone: function() {
        var plane = new Plane();
        plane.copy(this);
        return plane;
    }
};

/* harmony default export */ const math_Plane = (Plane);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Frustum.js





var Frustum_vec3Set = glmatrix_vec3.set;
var Frustum_vec3Copy = glmatrix_vec3.copy;
var vec3TranformMat4 = glmatrix_vec3.transformMat4;
var mathMin = Math.min;
var mathMax = Math.max;
/**
 * @constructor
 * @alias clay.Frustum
 */
var Frustum = function() {

    /**
     * Eight planes to enclose the frustum
     * @type {clay.Plane[]}
     */
    this.planes = [];

    for (var i = 0; i < 6; i++) {
        this.planes.push(new math_Plane());
    }

    /**
     * Bounding box of frustum
     * @type {clay.BoundingBox}
     */
    this.boundingBox = new math_BoundingBox();

    /**
     * Eight vertices of frustum
     * @type {Float32Array[]}
     */
    this.vertices = [];
    for (var i = 0; i < 8; i++) {
        this.vertices[i] = glmatrix_vec3.fromValues(0, 0, 0);
    }
};

Frustum.prototype = {

    // http://web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf
    /**
     * Set frustum from a projection matrix
     * @param {clay.Matrix4} projectionMatrix
     */
    setFromProjection: function(projectionMatrix) {

        var planes = this.planes;
        var m = projectionMatrix.array;
        var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
        var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7];
        var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11];
        var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15];

        // Update planes
        Frustum_vec3Set(planes[0].normal.array, m3 - m0, m7 - m4, m11 - m8);
        planes[0].distance = -(m15 - m12);
        planes[0].normalize();

        Frustum_vec3Set(planes[1].normal.array, m3 + m0, m7 + m4, m11 + m8);
        planes[1].distance = -(m15 + m12);
        planes[1].normalize();

        Frustum_vec3Set(planes[2].normal.array, m3 + m1, m7 + m5, m11 + m9);
        planes[2].distance = -(m15 + m13);
        planes[2].normalize();

        Frustum_vec3Set(planes[3].normal.array, m3 - m1, m7 - m5, m11 - m9);
        planes[3].distance = -(m15 - m13);
        planes[3].normalize();

        Frustum_vec3Set(planes[4].normal.array, m3 - m2, m7 - m6, m11 - m10);
        planes[4].distance = -(m15 - m14);
        planes[4].normalize();

        Frustum_vec3Set(planes[5].normal.array, m3 + m2, m7 + m6, m11 + m10);
        planes[5].distance = -(m15 + m14);
        planes[5].normalize();

        // Perspective projection
        var boundingBox = this.boundingBox;
        var vertices = this.vertices;
        if (m15 === 0)  {
            var aspect = m5 / m0;
            var zNear = -m14 / (m10 - 1);
            var zFar = -m14 / (m10 + 1);
            var farY = -zFar / m5;
            var nearY = -zNear / m5;
            // Update bounding box
            boundingBox.min.set(-farY * aspect, -farY, zFar);
            boundingBox.max.set(farY * aspect, farY, zNear);
            // update vertices
            //--- min z
            // min x
            Frustum_vec3Set(vertices[0], -farY * aspect, -farY, zFar);
            Frustum_vec3Set(vertices[1], -farY * aspect, farY, zFar);
            // max x
            Frustum_vec3Set(vertices[2], farY * aspect, -farY, zFar);
            Frustum_vec3Set(vertices[3], farY * aspect, farY, zFar);
            //-- max z
            Frustum_vec3Set(vertices[4], -nearY * aspect, -nearY, zNear);
            Frustum_vec3Set(vertices[5], -nearY * aspect, nearY, zNear);
            Frustum_vec3Set(vertices[6], nearY * aspect, -nearY, zNear);
            Frustum_vec3Set(vertices[7], nearY * aspect, nearY, zNear);
        }
        else { // Orthographic projection
            var left = (-1 - m12) / m0;
            var right = (1 - m12) / m0;
            var top = (1 - m13) / m5;
            var bottom = (-1 - m13) / m5;
            var near = (-1 - m14) / m10;
            var far = (1 - m14) / m10;


            boundingBox.min.set(Math.min(left, right), Math.min(bottom, top), Math.min(far, near));
            boundingBox.max.set(Math.max(right, left), Math.max(top, bottom), Math.max(near, far));

            var min = boundingBox.min.array;
            var max = boundingBox.max.array;
            //--- min z
            // min x
            Frustum_vec3Set(vertices[0], min[0], min[1], min[2]);
            Frustum_vec3Set(vertices[1], min[0], max[1], min[2]);
            // max x
            Frustum_vec3Set(vertices[2], max[0], min[1], min[2]);
            Frustum_vec3Set(vertices[3], max[0], max[1], min[2]);
            //-- max z
            Frustum_vec3Set(vertices[4], min[0], min[1], max[2]);
            Frustum_vec3Set(vertices[5], min[0], max[1], max[2]);
            Frustum_vec3Set(vertices[6], max[0], min[1], max[2]);
            Frustum_vec3Set(vertices[7], max[0], max[1], max[2]);
        }
    },

    /**
     * Apply a affine transform matrix and set to the given bounding box
     * @function
     * @param {clay.BoundingBox}
     * @param {clay.Matrix4}
     * @return {clay.BoundingBox}
     */
    getTransformedBoundingBox: (function() {

        var tmpVec3 = glmatrix_vec3.create();

        return function(bbox, matrix) {
            var vertices = this.vertices;

            var m4 = matrix.array;
            var min = bbox.min;
            var max = bbox.max;
            var minArr = min.array;
            var maxArr = max.array;
            var v = vertices[0];
            vec3TranformMat4(tmpVec3, v, m4);
            Frustum_vec3Copy(minArr, tmpVec3);
            Frustum_vec3Copy(maxArr, tmpVec3);

            for (var i = 1; i < 8; i++) {
                v = vertices[i];
                vec3TranformMat4(tmpVec3, v, m4);

                minArr[0] = mathMin(tmpVec3[0], minArr[0]);
                minArr[1] = mathMin(tmpVec3[1], minArr[1]);
                minArr[2] = mathMin(tmpVec3[2], minArr[2]);

                maxArr[0] = mathMax(tmpVec3[0], maxArr[0]);
                maxArr[1] = mathMax(tmpVec3[1], maxArr[1]);
                maxArr[2] = mathMax(tmpVec3[2], maxArr[2]);
            }

            min._dirty = true;
            max._dirty = true;

            return bbox;
        };
    }) ()
};
/* harmony default export */ const math_Frustum = (Frustum);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Camera.js









/**
 * @constructor clay.Camera
 * @extends clay.Node
 */
var Camera = src_Node.extend(function () {
    return /** @lends clay.Camera# */ {
        /**
         * Camera projection matrix
         * @type {clay.Matrix4}
         */
        projectionMatrix: new math_Matrix4(),

        /**
         * Inverse of camera projection matrix
         * @type {clay.Matrix4}
         */
        invProjectionMatrix: new math_Matrix4(),

        /**
         * View matrix, equal to inverse of camera's world matrix
         * @type {clay.Matrix4}
         */
        viewMatrix: new math_Matrix4(),

        /**
         * Camera frustum in view space
         * @type {clay.Frustum}
         */
        frustum: new math_Frustum()
    };
}, function () {
    this.update(true);
},
/** @lends clay.Camera.prototype */
{

    update: function (force) {
        src_Node.prototype.update.call(this, force);
        math_Matrix4.invert(this.viewMatrix, this.worldTransform);

        this.updateProjectionMatrix();
        math_Matrix4.invert(this.invProjectionMatrix, this.projectionMatrix);

        this.frustum.setFromProjection(this.projectionMatrix);
    },

    /**
     * Set camera view matrix
     */
    setViewMatrix: function (viewMatrix) {
        math_Matrix4.copy(this.viewMatrix, viewMatrix);
        math_Matrix4.invert(this.worldTransform, viewMatrix);
        this.decomposeWorldTransform();
    },

    /**
     * Decompose camera projection matrix
     */
    decomposeProjectionMatrix: function () {},

    /**
     * Set camera projection matrix
     * @param {clay.Matrix4} projectionMatrix
     */
    setProjectionMatrix: function (projectionMatrix) {
        math_Matrix4.copy(this.projectionMatrix, projectionMatrix);
        math_Matrix4.invert(this.invProjectionMatrix, projectionMatrix);
        this.decomposeProjectionMatrix();
    },
    /**
     * Update projection matrix, called after update
     */
    updateProjectionMatrix: function () {},

    /**
     * Cast a picking ray from camera near plane to far plane
     * @function
     * @param {clay.Vector2} ndc
     * @param {clay.Ray} [out]
     * @return {clay.Ray}
     */
    castRay: (function () {
        var v4 = glmatrix_vec4.create();
        return function (ndc, out) {
            var ray = out !== undefined ? out : new math_Ray();
            var x = ndc.array[0];
            var y = ndc.array[1];
            glmatrix_vec4.set(v4, x, y, -1, 1);
            glmatrix_vec4.transformMat4(v4, v4, this.invProjectionMatrix.array);
            glmatrix_vec4.transformMat4(v4, v4, this.worldTransform.array);
            glmatrix_vec3.scale(ray.origin.array, v4, 1 / v4[3]);

            glmatrix_vec4.set(v4, x, y, 1, 1);
            glmatrix_vec4.transformMat4(v4, v4, this.invProjectionMatrix.array);
            glmatrix_vec4.transformMat4(v4, v4, this.worldTransform.array);
            glmatrix_vec3.scale(v4, v4, 1 / v4[3]);
            glmatrix_vec3.sub(ray.direction.array, v4, ray.origin.array);

            glmatrix_vec3.normalize(ray.direction.array, ray.direction.array);
            ray.direction._dirty = true;
            ray.origin._dirty = true;

            return ray;
        };
    })(),

    /**
     * @function
     * @name clone
     * @return {clay.Camera}
     * @memberOf clay.Camera.prototype
     */
});

/* harmony default export */ const src_Camera = (Camera);

;// CONCATENATED MODULE: ./node_modules/claygl/src/Scene.js









var IDENTITY = glmatrix_mat4.create();
var WORLDVIEW = glmatrix_mat4.create();

var Scene_programKeyCache = {};

function Scene_getProgramKey(lightNumbers) {
    var defineStr = [];
    var lightTypes = Object.keys(lightNumbers);
    lightTypes.sort();
    for (var i = 0; i < lightTypes.length; i++) {
        var lightType = lightTypes[i];
        defineStr.push(lightType + ' ' + lightNumbers[lightType]);
    }
    var key = defineStr.join('\n');

    if (Scene_programKeyCache[key]) {
        return Scene_programKeyCache[key];
    }

    var id = core_util.genGUID();
    Scene_programKeyCache[key] = id;
    return id;
}

function RenderList() {

    this.opaque = [];
    this.transparent = [];

    this._opaqueCount = 0;
    this._transparentCount = 0;
}

RenderList.prototype.startCount = function () {
    this._opaqueCount = 0;
    this._transparentCount = 0;
};

RenderList.prototype.add = function (object, isTransparent) {
    if (isTransparent) {
        this.transparent[this._transparentCount++] = object;
    }
    else {
        this.opaque[this._opaqueCount++] = object;
    }
};

RenderList.prototype.endCount = function () {
    this.transparent.length = this._transparentCount;
    this.opaque.length = this._opaqueCount;
};

/**
 * @typedef {Object} clay.Scene.RenderList
 * @property {Array.<clay.Renderable>} opaque
 * @property {Array.<clay.Renderable>} transparent
 */

/**
 * @constructor clay.Scene
 * @extends clay.Node
 */
var Scene = src_Node.extend(function () {
    return /** @lends clay.Scene# */ {
        /**
         * Global material of scene
         * @type {clay.Material}
         */
        material: null,

        lights: [],

        /**
         * Scene bounding box in view space.
         * Used when camera needs to adujst the near and far plane automatically
         * so that the view frustum contains the visible objects as tightly as possible.
         * Notice:
         *  It is updated after rendering (in the step of frustum culling passingly). So may be not so accurate, but saves a lot of calculation
         *
         * @type {clay.BoundingBox}
         */
        viewBoundingBoxLastFrame: new math_BoundingBox(),

        // Uniforms for shadow map.
        shadowUniforms: {},

        _cameraList: [],

        // Properties to save the light information in the scene
        // Will be set in the render function
        _lightUniforms: {},

        _previousLightNumber: {},

        _lightNumber: {
            // groupId: {
                // POINT_LIGHT: 0,
                // DIRECTIONAL_LIGHT: 0,
                // SPOT_LIGHT: 0,
                // AMBIENT_LIGHT: 0,
                // AMBIENT_SH_LIGHT: 0
            // }
        },

        _lightProgramKeys: {},

        _nodeRepository: {},

        _renderLists: new core_LRU(20)

    };
}, function () {
    this._scene = this;
},
/** @lends clay.Scene.prototype. */
{

    // Add node to scene
    addToScene: function (node) {
        if (node instanceof src_Camera) {
            if (this._cameraList.length > 0) {
                console.warn('Found multiple camera in one scene. Use the fist one.');
            }
            this._cameraList.push(node);
        }
        else if (node instanceof src_Light) {
            this.lights.push(node);
        }
        if (node.name) {
            this._nodeRepository[node.name] = node;
        }
    },

    // Remove node from scene
    removeFromScene: function (node) {
        var idx;
        if (node instanceof src_Camera) {
            idx = this._cameraList.indexOf(node);
            if (idx >= 0) {
                this._cameraList.splice(idx, 1);
            }
        }
        else if (node instanceof src_Light) {
            idx = this.lights.indexOf(node);
            if (idx >= 0) {
                this.lights.splice(idx, 1);
            }
        }
        if (node.name) {
            delete this._nodeRepository[node.name];
        }
    },

    /**
     * Get node by name
     * @param  {string} name
     * @return {Node}
     * @DEPRECATED
     */
    getNode: function (name) {
        return this._nodeRepository[name];
    },

    /**
     * Set main camera of the scene.
     * @param {claygl.Camera} camera
     */
    setMainCamera: function (camera) {
        var idx = this._cameraList.indexOf(camera);
        if (idx >= 0) {
            this._cameraList.splice(idx, 1);
        }
        this._cameraList.unshift(camera);
    },
    /**
     * Get main camera of the scene.
     */
    getMainCamera: function () {
        return this._cameraList[0];
    },

    getLights: function () {
        return this.lights;
    },

    updateLights: function () {
        var lights = this.lights;
        this._previousLightNumber = this._lightNumber;

        var lightNumber = {};
        for (var i = 0; i < lights.length; i++) {
            var light = lights[i];
            if (light.invisible) {
                continue;
            }
            var group = light.group;
            if (!lightNumber[group]) {
                lightNumber[group] = {};
            }
            // User can use any type of light
            lightNumber[group][light.type] = lightNumber[group][light.type] || 0;
            lightNumber[group][light.type]++;
        }
        this._lightNumber = lightNumber;

        for (var groupId in lightNumber) {
            this._lightProgramKeys[groupId] = Scene_getProgramKey(lightNumber[groupId]);
        }

        this._updateLightUniforms();
    },

    /**
     * Clone a node and it's children, including mesh, camera, light, etc.
     * Unlike using `Node#clone`. It will clone skeleton and remap the joints. Material will also be cloned.
     *
     * @param {clay.Node} node
     * @return {clay.Node}
     */
    cloneNode: function (node) {
        var newNode = node.clone();
        var clonedNodesMap = {};
        function buildNodesMap(sNode, tNode) {
            clonedNodesMap[sNode.__uid__] = tNode;

            for (var i = 0; i < sNode._children.length; i++) {
                var sChild = sNode._children[i];
                var tChild = tNode._children[i];
                buildNodesMap(sChild, tChild);
            }
        }
        buildNodesMap(node, newNode);

        newNode.traverse(function (newChild) {
            if (newChild.skeleton) {
                newChild.skeleton = newChild.skeleton.clone(clonedNodesMap);
            }
            if (newChild.material) {
                newChild.material = newChild.material.clone();
            }
        });

        return newNode;
    },

    /**
     * Traverse the scene and add the renderable object to the render list.
     * It needs camera for the frustum culling.
     *
     * @param {clay.Camera} camera
     * @param {boolean} updateSceneBoundingBox
     * @return {clay.Scene.RenderList}
     */
    updateRenderList: function (camera, updateSceneBoundingBox) {
        var id = camera.__uid__;
        var renderList = this._renderLists.get(id);
        if (!renderList) {
            renderList = new RenderList();
            this._renderLists.put(id, renderList);
        }
        renderList.startCount();

        if (updateSceneBoundingBox) {
            this.viewBoundingBoxLastFrame.min.set(Infinity, Infinity, Infinity);
            this.viewBoundingBoxLastFrame.max.set(-Infinity, -Infinity, -Infinity);
        }

        var sceneMaterialTransparent = this.material && this.material.transparent || false;
        this._doUpdateRenderList(this, camera, sceneMaterialTransparent, renderList, updateSceneBoundingBox);

        renderList.endCount();

        return renderList;
    },

    /**
     * Get render list. Used after {@link clay.Scene#updateRenderList}
     * @param {clay.Camera} camera
     * @return {clay.Scene.RenderList}
     */
    getRenderList: function (camera) {
        return this._renderLists.get(camera.__uid__);
    },

    _doUpdateRenderList: function (parent, camera, sceneMaterialTransparent, renderList, updateSceneBoundingBox) {
        if (parent.invisible) {
            return;
        }
        // TODO Optimize
        for (var i = 0; i < parent._children.length; i++) {
            var child = parent._children[i];

            if (child.isRenderable()) {
                // Frustum culling
                var worldM = child.isSkinnedMesh() ? IDENTITY : child.worldTransform.array;
                var geometry = child.geometry;

                glmatrix_mat4.multiplyAffine(WORLDVIEW, camera.viewMatrix.array, worldM);
                if (updateSceneBoundingBox && !geometry.boundingBox || !this.isFrustumCulled(child, camera, WORLDVIEW)) {
                    renderList.add(child, child.material.transparent || sceneMaterialTransparent);
                }
            }
            if (child._children.length > 0) {
                this._doUpdateRenderList(child, camera, sceneMaterialTransparent, renderList, updateSceneBoundingBox);
            }
        }
    },

    /**
     * If an scene object is culled by camera frustum
     *
     * Object can be a renderable or a light
     *
     * @param {clay.Node} object
     * @param {clay.Camera} camera
     * @param {Array.<number>} worldViewMat represented with array
     * @param {Array.<number>} projectionMat represented with array
     */
    isFrustumCulled: (function () {
        // Frustum culling
        // http://www.cse.chalmers.se/~uffe/vfc_bbox.pdf
        var cullingBoundingBox = new math_BoundingBox();
        var cullingMatrix = new math_Matrix4();
        return function(object, camera, worldViewMat) {
            // Bounding box can be a property of object(like light) or renderable.geometry
            // PENDING
            var geoBBox = object.boundingBox;
            if (!geoBBox) {
                if (object.skeleton && object.skeleton.boundingBox) {
                    geoBBox = object.skeleton.boundingBox;
                }
                else {
                    geoBBox = object.geometry.boundingBox;
                }
            }

            if (!geoBBox) {
                return false;
            }

            cullingMatrix.array = worldViewMat;
            cullingBoundingBox.transformFrom(geoBBox, cullingMatrix);

            // Passingly update the scene bounding box
            // FIXME exclude very large mesh like ground plane or terrain ?
            // FIXME Only rendererable which cast shadow ?

            // FIXME boundingBox becomes much larger after transformd.
            if (object.castShadow) {
                this.viewBoundingBoxLastFrame.union(cullingBoundingBox);
            }
            // Ignore frustum culling if object is skinned mesh.
            if (object.frustumCulling)  {
                if (!cullingBoundingBox.intersectBoundingBox(camera.frustum.boundingBox)) {
                    return true;
                }

                cullingMatrix.array = camera.projectionMatrix.array;
                if (
                    cullingBoundingBox.max.array[2] > 0 &&
                    cullingBoundingBox.min.array[2] < 0
                ) {
                    // Clip in the near plane
                    cullingBoundingBox.max.array[2] = -1e-20;
                }

                cullingBoundingBox.applyProjection(cullingMatrix);

                var min = cullingBoundingBox.min.array;
                var max = cullingBoundingBox.max.array;

                if (
                    max[0] < -1 || min[0] > 1
                    || max[1] < -1 || min[1] > 1
                    || max[2] < -1 || min[2] > 1
                ) {
                    return true;
                }
            }

            return false;
        };
    })(),

    _updateLightUniforms: function () {
        var lights = this.lights;
        // Put the light cast shadow before the light not cast shadow
        lights.sort(lightSortFunc);

        var lightUniforms = this._lightUniforms;
        for (var group in lightUniforms) {
            for (var symbol in lightUniforms[group]) {
                lightUniforms[group][symbol].value.length = 0;
            }
        }
        for (var i = 0; i < lights.length; i++) {

            var light = lights[i];

            if (light.invisible) {
                continue;
            }

            var group = light.group;

            for (var symbol in light.uniformTemplates) {
                var uniformTpl = light.uniformTemplates[symbol];
                var value = uniformTpl.value(light);
                if (value == null) {
                    continue;
                }
                if (!lightUniforms[group]) {
                    lightUniforms[group] = {};
                }
                if (!lightUniforms[group][symbol]) {
                    lightUniforms[group][symbol] = {
                        type: '',
                        value: []
                    };
                }
                var lu = lightUniforms[group][symbol];
                lu.type = uniformTpl.type + 'v';
                switch (uniformTpl.type) {
                    case '1i':
                    case '1f':
                    case 't':
                        lu.value.push(value);
                        break;
                    case '2f':
                    case '3f':
                    case '4f':
                        for (var j = 0; j < value.length; j++) {
                            lu.value.push(value[j]);
                        }
                        break;
                    default:
                        console.error('Unkown light uniform type ' + uniformTpl.type);
                }
            }
        }
    },

    getLightGroups: function () {
        var lightGroups = [];
        for (var groupId in this._lightNumber) {
            lightGroups.push(groupId);
        }
        return lightGroups;
    },

    getNumberChangedLightGroups: function () {
        var lightGroups = [];
        for (var groupId in this._lightNumber) {
            if (this.isLightNumberChanged(groupId)) {
                lightGroups.push(groupId);
            }
        }
        return lightGroups;
    },

    // Determine if light group is different with since last frame
    // Used to determine whether to update shader and scene's uniforms in Renderer.render
    isLightNumberChanged: function (lightGroup) {
        var prevLightNumber = this._previousLightNumber;
        var currentLightNumber = this._lightNumber;
        // PENDING Performance
        for (var type in currentLightNumber[lightGroup]) {
            if (!prevLightNumber[lightGroup]) {
                return true;
            }
            if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) {
                return true;
            }
        }
        for (var type in prevLightNumber[lightGroup]) {
            if (!currentLightNumber[lightGroup]) {
                return true;
            }
            if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) {
                return true;
            }
        }
        return false;
    },

    getLightsNumbers: function (lightGroup) {
        return this._lightNumber[lightGroup];
    },

    getProgramKey: function (lightGroup) {
        return this._lightProgramKeys[lightGroup];
    },

    setLightUniforms: (function () {
        function setUniforms(uniforms, program, renderer) {
            for (var symbol in uniforms) {
                var lu = uniforms[symbol];
                if (lu.type === 'tv') {
                    if (!program.hasUniform(symbol)) {
                        continue;
                    }
                    var texSlots = [];
                    for (var i = 0; i < lu.value.length; i++) {
                        var texture = lu.value[i];
                        var slot = program.takeCurrentTextureSlot(renderer, texture);
                        texSlots.push(slot);
                    }
                    program.setUniform(renderer.gl, '1iv', symbol, texSlots);
                }
                else {
                    program.setUniform(renderer.gl, lu.type, symbol, lu.value);
                }
            }
        }

        return function (program, lightGroup, renderer) {
            setUniforms(this._lightUniforms[lightGroup], program, renderer);
            // Set shadows
            setUniforms(this.shadowUniforms, program, renderer);
        };
    })(),

    /**
     * Dispose self, clear all the scene objects
     * But resources of gl like texuture, shader will not be disposed.
     * Mostly you should use disposeScene method in Renderer to do dispose.
     */
    dispose: function () {
        this.material = null;
        this._opaqueList = [];
        this._transparentList = [];

        this.lights = [];

        this._lightUniforms = {};

        this._lightNumber = {};
        this._nodeRepository = {};
    }
});

function lightSortFunc(a, b) {
    if (b.castShadow && !a.castShadow) {
        return true;
    }
}

/* harmony default export */ const src_Scene = (Scene);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/LRU.js
var Entry = (function () {
    function Entry(val) {
        this.value = val;
    }
    return Entry;
}());

var LRU_LinkedList = (function () {
    function LinkedList() {
        this._len = 0;
    }
    LinkedList.prototype.insert = function (val) {
        var entry = new Entry(val);
        this.insertEntry(entry);
        return entry;
    };
    LinkedList.prototype.insertEntry = function (entry) {
        if (!this.head) {
            this.head = this.tail = entry;
        }
        else {
            this.tail.next = entry;
            entry.prev = this.tail;
            entry.next = null;
            this.tail = entry;
        }
        this._len++;
    };
    LinkedList.prototype.remove = function (entry) {
        var prev = entry.prev;
        var next = entry.next;
        if (prev) {
            prev.next = next;
        }
        else {
            this.head = next;
        }
        if (next) {
            next.prev = prev;
        }
        else {
            this.tail = prev;
        }
        entry.next = entry.prev = null;
        this._len--;
    };
    LinkedList.prototype.len = function () {
        return this._len;
    };
    LinkedList.prototype.clear = function () {
        this.head = this.tail = null;
        this._len = 0;
    };
    return LinkedList;
}());

var LRU_LRU = (function () {
    function LRU(maxSize) {
        this._list = new LRU_LinkedList();
        this._maxSize = 10;
        this._map = {};
        this._maxSize = maxSize;
    }
    LRU.prototype.put = function (key, value) {
        var list = this._list;
        var map = this._map;
        var removed = null;
        if (map[key] == null) {
            var len = list.len();
            var entry = this._lastRemovedEntry;
            if (len >= this._maxSize && len > 0) {
                var leastUsedEntry = list.head;
                list.remove(leastUsedEntry);
                delete map[leastUsedEntry.key];
                removed = leastUsedEntry.value;
                this._lastRemovedEntry = leastUsedEntry;
            }
            if (entry) {
                entry.value = value;
            }
            else {
                entry = new Entry(value);
            }
            entry.key = key;
            list.insertEntry(entry);
            map[key] = entry;
        }
        return removed;
    };
    LRU.prototype.get = function (key) {
        var entry = this._map[key];
        var list = this._list;
        if (entry != null) {
            if (entry !== list.tail) {
                list.remove(entry);
                list.insertEntry(entry);
            }
            return entry.value;
        }
    };
    LRU.prototype.clear = function () {
        this._list.clear();
        this._map = {};
    };
    LRU.prototype.len = function () {
        return this._list.len();
    };
    return LRU;
}());
/* harmony default export */ const lib_core_LRU = (LRU_LRU);

;// CONCATENATED MODULE: ./node_modules/claygl/src/TextureCube.js





var TextureCube_isPowerOfTwo = math_util.isPowerOfTwo;

var targetList = ['px', 'nx', 'py', 'ny', 'pz', 'nz'];

/**
 * @constructor clay.TextureCube
 * @extends clay.Texture
 *
 * @example
 *     ...
 *     var mat = new clay.Material({
 *         shader: clay.shader.library.get('clay.phong', 'environmentMap')
 *     });
 *     var envMap = new clay.TextureCube();
 *     envMap.load({
 *         'px': 'assets/textures/sky/px.jpg',
 *         'nx': 'assets/textures/sky/nx.jpg'
 *         'py': 'assets/textures/sky/py.jpg'
 *         'ny': 'assets/textures/sky/ny.jpg'
 *         'pz': 'assets/textures/sky/pz.jpg'
 *         'nz': 'assets/textures/sky/nz.jpg'
 *     });
 *     mat.set('environmentMap', envMap);
 *     ...
 *     envMap.success(function () {
 *         // Wait for the sky texture loaded
 *         animation.on('frame', function (frameTime) {
 *             renderer.render(scene, camera);
 *         });
 *     });
 */
var TextureCube = src_Texture.extend(function () {
    return /** @lends clay.TextureCube# */{

        /**
         * @type {boolean}
         * @default false
         */
        // PENDING cubemap should not flipY in default.
        // flipY: false,

        /**
         * @type {Object}
         * @property {?HTMLImageElement|HTMLCanvasElemnet} px
         * @property {?HTMLImageElement|HTMLCanvasElemnet} nx
         * @property {?HTMLImageElement|HTMLCanvasElemnet} py
         * @property {?HTMLImageElement|HTMLCanvasElemnet} ny
         * @property {?HTMLImageElement|HTMLCanvasElemnet} pz
         * @property {?HTMLImageElement|HTMLCanvasElemnet} nz
         */
        image: {
            px: null,
            nx: null,
            py: null,
            ny: null,
            pz: null,
            nz: null
        },
        /**
         * Pixels data of each side. Will be ignored if images are set.
         * @type {Object}
         * @property {?Uint8Array} px
         * @property {?Uint8Array} nx
         * @property {?Uint8Array} py
         * @property {?Uint8Array} ny
         * @property {?Uint8Array} pz
         * @property {?Uint8Array} nz
         */
        pixels: {
            px: null,
            nx: null,
            py: null,
            ny: null,
            pz: null,
            nz: null
        },

        /**
         * @type {Array.<Object>}
         */
        mipmaps: []
    };
}, {

    textureType: 'textureCube',

    update: function (renderer) {
        var _gl = renderer.gl;
        _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, this._cache.get('webgl_texture'));

        this.updateCommon(renderer);

        var glFormat = this.format;
        var glType = this.type;

        _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_S, this.getAvailableWrapS());
        _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_T, this.getAvailableWrapT());

        _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MAG_FILTER, this.getAvailableMagFilter());
        _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MIN_FILTER, this.getAvailableMinFilter());

        var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic');
        if (anisotropicExt && this.anisotropic > 1) {
            _gl.texParameterf(_gl.TEXTURE_CUBE_MAP, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic);
        }

        // Fallback to float type if browser don't have half float extension
        if (glType === 36193) {
            var halfFloatExt = renderer.getGLExtension('OES_texture_half_float');
            if (!halfFloatExt) {
                glType = glenum.FLOAT;
            }
        }

        if (this.mipmaps.length) {
            var width = this.width;
            var height = this.height;
            for (var i = 0; i < this.mipmaps.length; i++) {
                var mipmap = this.mipmaps[i];
                this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType);
                width /= 2;
                height /= 2;
            }
        }
        else {
            this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType);

            if (!this.NPOT && this.useMipmap) {
                _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP);
            }
        }

        _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, null);
    },

    _updateTextureData: function (_gl, data, level, width, height, glFormat, glType) {
        for (var i = 0; i < 6; i++) {
            var target = targetList[i];
            var img = data.image && data.image[target];
            if (img) {
                _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, glFormat, glFormat, glType, img);
            }
            else {
                _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, glFormat, width, height, 0, glFormat, glType, data.pixels && data.pixels[target]);
            }
        }
    },

    /**
     * @param  {clay.Renderer} renderer
     * @memberOf clay.TextureCube.prototype
     */
    generateMipmap: function (renderer) {
        var _gl = renderer.gl;
        if (this.useMipmap && !this.NPOT) {
            _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, this._cache.get('webgl_texture'));
            _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP);
        }
    },

    bind: function (renderer) {
        renderer.gl.bindTexture(renderer.gl.TEXTURE_CUBE_MAP, this.getWebGLTexture(renderer));
    },

    unbind: function (renderer) {
        renderer.gl.bindTexture(renderer.gl.TEXTURE_CUBE_MAP, null);
    },

    // Overwrite the isPowerOfTwo method
    isPowerOfTwo: function () {
        if (this.image.px) {
            return TextureCube_isPowerOfTwo(this.image.px.width)
                && TextureCube_isPowerOfTwo(this.image.px.height);
        }
        else {
            return TextureCube_isPowerOfTwo(this.width)
                && TextureCube_isPowerOfTwo(this.height);
        }
    },

    isRenderable: function () {
        if (this.image.px) {
            return isImageRenderable(this.image.px)
                && isImageRenderable(this.image.nx)
                && isImageRenderable(this.image.py)
                && isImageRenderable(this.image.ny)
                && isImageRenderable(this.image.pz)
                && isImageRenderable(this.image.nz);
        }
        else {
            return !!(this.width && this.height);
        }
    },

    load: function (imageList, crossOrigin) {
        var loading = 0;
        var self = this;
        core_util.each(imageList, function (src, target){
            var image = core_vendor.createImage();
            if (crossOrigin) {
                image.crossOrigin = crossOrigin;
            }
            image.onload = function () {
                loading --;
                if (loading === 0){
                    self.dirty();
                    self.trigger('success', self);
                }
            };
            image.onerror = function () {
                loading --;
            };

            loading++;
            image.src = src;
            self.image[target] = image;
        });

        return this;
    }
});

Object.defineProperty(TextureCube.prototype, 'width', {
    get: function () {
        if (this.image && this.image.px) {
            return this.image.px.width;
        }
        return this._width;
    },
    set: function (value) {
        if (this.image && this.image.px) {
            console.warn('Texture from image can\'t set width');
        }
        else {
            if (this._width !== value) {
                this.dirty();
            }
            this._width = value;
        }
    }
});
Object.defineProperty(TextureCube.prototype, 'height', {
    get: function () {
        if (this.image && this.image.px) {
            return this.image.px.height;
        }
        return this._height;
    },
    set: function (value) {
        if (this.image && this.image.px) {
            console.warn('Texture from image can\'t set height');
        }
        else {
            if (this._height !== value) {
                this.dirty();
            }
            this._height = value;
        }
    }
});
function isImageRenderable(image) {
    return image.width > 0 && image.height > 0;
}

/* harmony default export */ const src_TextureCube = (TextureCube);

;// CONCATENATED MODULE: ./node_modules/claygl/src/camera/Perspective.js


/**
 * @constructor clay.camera.Perspective
 * @extends clay.Camera
 */
var Perspective = src_Camera.extend(/** @lends clay.camera.Perspective# */{
    /**
     * Vertical field of view in degrees
     * @type {number}
     */
    fov: 50,
    /**
     * Aspect ratio, typically viewport width / height
     * @type {number}
     */
    aspect: 1,
    /**
     * Near bound of the frustum
     * @type {number}
     */
    near: 0.1,
    /**
     * Far bound of the frustum
     * @type {number}
     */
    far: 2000
},
/** @lends clay.camera.Perspective.prototype */
{

    updateProjectionMatrix: function() {
        var rad = this.fov / 180 * Math.PI;
        this.projectionMatrix.perspective(rad, this.aspect, this.near, this.far);
    },
    decomposeProjectionMatrix: function () {
        var m = this.projectionMatrix.array;
        var rad = Math.atan(1 / m[5]) * 2;
        this.fov = rad / Math.PI * 180;
        this.aspect = m[5] / m[0];
        this.near = m[14] / (m[10] - 1);
        this.far = m[14] / (m[10] + 1);
    },
    /**
     * @return {clay.camera.Perspective}
     */
    clone: function() {
        var camera = src_Camera.prototype.clone.call(this);
        camera.fov = this.fov;
        camera.aspect = this.aspect;
        camera.near = this.near;
        camera.far = this.far;

        return camera;
    }
});

/* harmony default export */ const camera_Perspective = (Perspective);

;// CONCATENATED MODULE: ./node_modules/claygl/src/FrameBuffer.js






var KEY_FRAMEBUFFER = 'framebuffer';
var KEY_RENDERBUFFER = 'renderbuffer';
var KEY_RENDERBUFFER_WIDTH = KEY_RENDERBUFFER + '_width';
var KEY_RENDERBUFFER_HEIGHT = KEY_RENDERBUFFER + '_height';
var KEY_RENDERBUFFER_ATTACHED = KEY_RENDERBUFFER + '_attached';
var KEY_DEPTHTEXTURE_ATTACHED = 'depthtexture_attached';

var GL_FRAMEBUFFER = glenum.FRAMEBUFFER;
var GL_RENDERBUFFER = glenum.RENDERBUFFER;
var GL_DEPTH_ATTACHMENT = glenum.DEPTH_ATTACHMENT;
var GL_COLOR_ATTACHMENT0 = glenum.COLOR_ATTACHMENT0;
/**
 * @constructor clay.FrameBuffer
 * @extends clay.core.Base
 */
var FrameBuffer = core_Base.extend(
/** @lends clay.FrameBuffer# */
{
    /**
     * If use depth buffer
     * @type {boolean}
     */
    depthBuffer: true,

    /**
     * @type {Object}
     */
    viewport: null,

    _width: 0,
    _height: 0,

    _textures: null,

    _boundRenderer: null,
}, function () {
    // Use cache
    this._cache = new core_Cache();

    this._textures = {};
},

/**@lends clay.FrameBuffer.prototype. */
{
    /**
     * Get attached texture width
     * {number}
     */
    // FIXME Can't use before #bind
    getTextureWidth: function () {
        return this._width;
    },

    /**
     * Get attached texture height
     * {number}
     */
    getTextureHeight: function () {
        return this._height;
    },

    /**
     * Bind the framebuffer to given renderer before rendering
     * @param  {clay.Renderer} renderer
     */
    bind: function (renderer) {

        if (renderer.__currentFrameBuffer) {
            // Already bound
            if (renderer.__currentFrameBuffer === this) {
                return;
            }

            console.warn('Renderer already bound with another framebuffer. Unbind it first');
        }
        renderer.__currentFrameBuffer = this;

        var _gl = renderer.gl;

        _gl.bindFramebuffer(GL_FRAMEBUFFER, this._getFrameBufferGL(renderer));
        this._boundRenderer = renderer;
        var cache = this._cache;

        cache.put('viewport', renderer.viewport);

        var hasTextureAttached = false;
        var width;
        var height;
        for (var attachment in this._textures) {
            hasTextureAttached = true;
            var obj = this._textures[attachment];
            if (obj) {
                // TODO Do width, height checking, make sure size are same
                width = obj.texture.width;
                height = obj.texture.height;
                // Attach textures
                this._doAttach(renderer, obj.texture, attachment, obj.target);
            }
        }

        this._width = width;
        this._height = height;

        if (!hasTextureAttached && this.depthBuffer) {
            console.error('Must attach texture before bind, or renderbuffer may have incorrect width and height.')
        }

        if (this.viewport) {
            renderer.setViewport(this.viewport);
        }
        else {
            renderer.setViewport(0, 0, width, height, 1);
        }

        var attachedTextures = cache.get('attached_textures');
        if (attachedTextures) {
            for (var attachment in attachedTextures) {
                if (!this._textures[attachment]) {
                    var target = attachedTextures[attachment];
                    this._doDetach(_gl, attachment, target);
                }
            }
        }
        if (!cache.get(KEY_DEPTHTEXTURE_ATTACHED) && this.depthBuffer) {
            // Create a new render buffer
            if (cache.miss(KEY_RENDERBUFFER)) {
                cache.put(KEY_RENDERBUFFER, _gl.createRenderbuffer());
            }
            var renderbuffer = cache.get(KEY_RENDERBUFFER);

            if (width !== cache.get(KEY_RENDERBUFFER_WIDTH)
                    || height !== cache.get(KEY_RENDERBUFFER_HEIGHT)) {
                _gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
                _gl.renderbufferStorage(GL_RENDERBUFFER, _gl.DEPTH_COMPONENT16, width, height);
                cache.put(KEY_RENDERBUFFER_WIDTH, width);
                cache.put(KEY_RENDERBUFFER_HEIGHT, height);
                _gl.bindRenderbuffer(GL_RENDERBUFFER, null);
            }
            if (!cache.get(KEY_RENDERBUFFER_ATTACHED)) {
                _gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
                cache.put(KEY_RENDERBUFFER_ATTACHED, true);
            }
        }
    },

    /**
     * Unbind the frame buffer after rendering
     * @param  {clay.Renderer} renderer
     */
    unbind: function (renderer) {
        // Remove status record on renderer
        renderer.__currentFrameBuffer = null;

        var _gl = renderer.gl;

        _gl.bindFramebuffer(GL_FRAMEBUFFER, null);
        this._boundRenderer = null;

        this._cache.use(renderer.__uid__);
        var viewport = this._cache.get('viewport');
        // Reset viewport;
        if (viewport) {
            renderer.setViewport(viewport);
        }

        this.updateMipmap(renderer);
    },

    // Because the data of texture is changed over time,
    // Here update the mipmaps of texture each time after rendered;
    updateMipmap: function (renderer) {
        var _gl = renderer.gl;
        for (var attachment in this._textures) {
            var obj = this._textures[attachment];
            if (obj) {
                var texture = obj.texture;
                // FIXME some texture format can't generate mipmap
                if (!texture.NPOT && texture.useMipmap
                    && texture.minFilter === src_Texture.LINEAR_MIPMAP_LINEAR) {
                    var target = texture.textureType === 'textureCube' ? glenum.TEXTURE_CUBE_MAP : glenum.TEXTURE_2D;
                    _gl.bindTexture(target, texture.getWebGLTexture(renderer));
                    _gl.generateMipmap(target);
                    _gl.bindTexture(target, null);
                }
            }
        }
    },


    // 0x8CD5, 36053, FRAMEBUFFER_COMPLETE
    // 0x8CD6, 36054, FRAMEBUFFER_INCOMPLETE_ATTACHMENT
    // 0x8CD7, 36055, FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
    // 0x8CD9, 36057, FRAMEBUFFER_INCOMPLETE_DIMENSIONS
    // 0x8CDD, 36061, FRAMEBUFFER_UNSUPPORTED
    checkStatus: function (_gl) {
        return _gl.checkFramebufferStatus(GL_FRAMEBUFFER);
    },

    _getFrameBufferGL: function (renderer) {
        var cache = this._cache;
        cache.use(renderer.__uid__);

        if (cache.miss(KEY_FRAMEBUFFER)) {
            cache.put(KEY_FRAMEBUFFER, renderer.gl.createFramebuffer());
        }

        return cache.get(KEY_FRAMEBUFFER);
    },

    /**
     * Attach a texture(RTT) to the framebuffer
     * @param  {clay.Texture} texture
     * @param  {number} [attachment=gl.COLOR_ATTACHMENT0]
     * @param  {number} [target=gl.TEXTURE_2D]
     */
    attach: function (texture, attachment, target) {

        if (!texture.width) {
            throw new Error('The texture attached to color buffer is not a valid.');
        }
        // TODO width and height check

        // If the depth_texture extension is enabled, developers
        // Can attach a depth texture to the depth buffer
        // http://blog.tojicode.com/2012/07/using-webgldepthtexture.html
        attachment = attachment || GL_COLOR_ATTACHMENT0;
        target = target || glenum.TEXTURE_2D;

        var boundRenderer = this._boundRenderer;
        var _gl = boundRenderer && boundRenderer.gl;
        var attachedTextures;

        if (_gl) {
            var cache = this._cache;
            cache.use(boundRenderer.__uid__);
            attachedTextures = cache.get('attached_textures');
        }

        // Check if texture attached
        var previous = this._textures[attachment];
        if (previous && previous.target === target
            && previous.texture === texture
            && (attachedTextures && attachedTextures[attachment] != null)
        ) {
            return;
        }

        var canAttach = true;
        if (boundRenderer) {
            canAttach = this._doAttach(boundRenderer, texture, attachment, target);
            // Set viewport again incase attached to different size textures.
            if (!this.viewport) {
                boundRenderer.setViewport(0, 0, texture.width, texture.height, 1);
            }
        }

        if (canAttach) {
            this._textures[attachment] = this._textures[attachment] || {};
            this._textures[attachment].texture = texture;
            this._textures[attachment].target = target;
        }
    },

    _doAttach: function (renderer, texture, attachment, target) {
        var _gl = renderer.gl;
        // Make sure texture is always updated
        // Because texture width or height may be changed and in this we can't be notified
        // FIXME awkward;
        var webglTexture = texture.getWebGLTexture(renderer);
        // Assume cache has been used.
        var attachedTextures = this._cache.get('attached_textures');
        if (attachedTextures && attachedTextures[attachment]) {
            var obj = attachedTextures[attachment];
            // Check if texture and target not changed
            if (obj.texture === texture && obj.target === target) {
                return;
            }
        }
        attachment = +attachment;

        var canAttach = true;
        if (attachment === GL_DEPTH_ATTACHMENT || attachment === glenum.DEPTH_STENCIL_ATTACHMENT) {
            var extension = renderer.getGLExtension('WEBGL_depth_texture');

            if (!extension) {
                console.error('Depth texture is not supported by the browser');
                canAttach = false;
            }
            if (texture.format !== glenum.DEPTH_COMPONENT
                && texture.format !== glenum.DEPTH_STENCIL
            ) {
                console.error('The texture attached to depth buffer is not a valid.');
                canAttach = false;
            }

            // Dispose render buffer created previous
            if (canAttach) {
                var renderbuffer = this._cache.get(KEY_RENDERBUFFER);
                if (renderbuffer) {
                    _gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, null);
                    _gl.deleteRenderbuffer(renderbuffer);
                    this._cache.put(KEY_RENDERBUFFER, false);
                }

                this._cache.put(KEY_RENDERBUFFER_ATTACHED, false);
                this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, true);
            }
        }

        // Mipmap level can only be 0
        _gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, webglTexture, 0);

        if (!attachedTextures) {
            attachedTextures = {};
            this._cache.put('attached_textures', attachedTextures);
        }
        attachedTextures[attachment] = attachedTextures[attachment] || {};
        attachedTextures[attachment].texture = texture;
        attachedTextures[attachment].target = target;

        return canAttach;
    },

    _doDetach: function (_gl, attachment, target) {
        // Detach a texture from framebuffer
        // https://github.com/KhronosGroup/WebGL/blob/master/conformance-suites/1.0.0/conformance/framebuffer-test.html#L145
        _gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, null, 0);

        // Assume cache has been used.
        var attachedTextures = this._cache.get('attached_textures');
        if (attachedTextures && attachedTextures[attachment]) {
            attachedTextures[attachment] = null;
        }

        if (attachment === GL_DEPTH_ATTACHMENT || attachment === glenum.DEPTH_STENCIL_ATTACHMENT) {
            this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, false);
        }
    },

    /**
     * Detach a texture
     * @param  {number} [attachment=gl.COLOR_ATTACHMENT0]
     * @param  {number} [target=gl.TEXTURE_2D]
     */
    detach: function (attachment, target) {
        // TODO depth extension check ?
        this._textures[attachment] = null;
        if (this._boundRenderer) {
            var cache = this._cache;
            cache.use(this._boundRenderer.__uid__);
            this._doDetach(this._boundRenderer.gl, attachment, target);
        }
    },
    /**
     * Dispose
     * @param  {WebGLRenderingContext} _gl
     */
    dispose: function (renderer) {

        var _gl = renderer.gl;
        var cache = this._cache;

        cache.use(renderer.__uid__);

        var renderBuffer = cache.get(KEY_RENDERBUFFER);
        if (renderBuffer) {
            _gl.deleteRenderbuffer(renderBuffer);
        }
        var frameBuffer = cache.get(KEY_FRAMEBUFFER);
        if (frameBuffer) {
            _gl.deleteFramebuffer(frameBuffer);
        }
        cache.deleteContext(renderer.__uid__);

        // Clear cache for reusing
        this._textures = {};

    }
});

FrameBuffer.DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT;
FrameBuffer.COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0;
FrameBuffer.STENCIL_ATTACHMENT = glenum.STENCIL_ATTACHMENT;
FrameBuffer.DEPTH_STENCIL_ATTACHMENT = glenum.DEPTH_STENCIL_ATTACHMENT;

/* harmony default export */ const src_FrameBuffer = (FrameBuffer);

;// CONCATENATED MODULE: ./node_modules/claygl/src/prePass/EnvironmentMap.js





var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz'];

/**
 * Pass rendering scene to a environment cube map
 *
 * @constructor clay.prePass.EnvironmentMap
 * @extends clay.core.Base
 * @example
 *     // Example of car reflection
 *     var envMap = new clay.TextureCube({
 *         width: 256,
 *         height: 256
 *     });
 *     var envPass = new clay.prePass.EnvironmentMap({
 *         position: car.position,
 *         texture: envMap
 *     });
 *     var carBody = car.getChildByName('body');
 *     carBody.material.enableTexture('environmentMap');
 *     carBody.material.set('environmentMap', envMap);
 *     ...
 *     animation.on('frame', function(frameTime) {
 *         envPass.render(renderer, scene);
 *         renderer.render(scene, camera);
 *     });
 */
var EnvironmentMapPass = core_Base.extend(function() {
    var ret = /** @lends clay.prePass.EnvironmentMap# */ {
        /**
         * Camera position
         * @type {clay.Vector3}
         * @memberOf clay.prePass.EnvironmentMap#
         */
        position: new math_Vector3(),
        /**
         * Camera far plane
         * @type {number}
         * @memberOf clay.prePass.EnvironmentMap#
         */
        far: 1000,
        /**
         * Camera near plane
         * @type {number}
         * @memberOf clay.prePass.EnvironmentMap#
         */
        near: 0.1,
        /**
         * Environment cube map
         * @type {clay.TextureCube}
         * @memberOf clay.prePass.EnvironmentMap#
         */
        texture: null,

        /**
         * Used if you wan't have shadow in environment map
         * @type {clay.prePass.ShadowMap}
         */
        shadowMapPass: null,
    };
    var cameras = ret._cameras = {
        px: new camera_Perspective({ fov: 90 }),
        nx: new camera_Perspective({ fov: 90 }),
        py: new camera_Perspective({ fov: 90 }),
        ny: new camera_Perspective({ fov: 90 }),
        pz: new camera_Perspective({ fov: 90 }),
        nz: new camera_Perspective({ fov: 90 })
    };
    cameras.px.lookAt(math_Vector3.POSITIVE_X, math_Vector3.NEGATIVE_Y);
    cameras.nx.lookAt(math_Vector3.NEGATIVE_X, math_Vector3.NEGATIVE_Y);
    cameras.py.lookAt(math_Vector3.POSITIVE_Y, math_Vector3.POSITIVE_Z);
    cameras.ny.lookAt(math_Vector3.NEGATIVE_Y, math_Vector3.NEGATIVE_Z);
    cameras.pz.lookAt(math_Vector3.POSITIVE_Z, math_Vector3.NEGATIVE_Y);
    cameras.nz.lookAt(math_Vector3.NEGATIVE_Z, math_Vector3.NEGATIVE_Y);

    // FIXME In windows, use one framebuffer only renders one side of cubemap
    ret._frameBuffer = new src_FrameBuffer();

    return ret;
},  /** @lends clay.prePass.EnvironmentMap# */ {
    /**
     * @param  {string} target
     * @return  {clay.Camera}
     */
    getCamera: function (target) {
        return this._cameras[target];
    },
    /**
     * @param  {clay.Renderer} renderer
     * @param  {clay.Scene} scene
     * @param  {boolean} [notUpdateScene=false]
     */
    render: function(renderer, scene, notUpdateScene) {
        var _gl = renderer.gl;
        if (!notUpdateScene) {
            scene.update();
        }
        // Tweak fov
        // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
        var n = this.texture.width;
        var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180;

        for (var i = 0; i < 6; i++) {
            var target = targets[i];
            var camera = this._cameras[target];
            math_Vector3.copy(camera.position, this.position);

            camera.far = this.far;
            camera.near = this.near;
            camera.fov = fov;

            if (this.shadowMapPass) {
                camera.update();

                // update boundingBoxLastFrame
                var bbox = scene.getBoundingBox();
                bbox.applyTransform(camera.viewMatrix);
                scene.viewBoundingBoxLastFrame.copy(bbox);

                this.shadowMapPass.render(renderer, scene, camera, true);
            }
            this._frameBuffer.attach(
                this.texture, _gl.COLOR_ATTACHMENT0,
                _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i
            );
            this._frameBuffer.bind(renderer);
            renderer.render(scene, camera, true);
            this._frameBuffer.unbind(renderer);
        }
    },
    /**
     * @param {clay.Renderer} renderer
     */
    dispose: function (renderer) {
        this._frameBuffer.dispose(renderer);
    }
});

/* harmony default export */ const EnvironmentMap = (EnvironmentMapPass);

;// CONCATENATED MODULE: ./node_modules/claygl/src/geometry/Plane.js



/**
 * @constructor clay.geometry.Plane
 * @extends clay.Geometry
 * @param {Object} [opt]
 * @param {number} [opt.widthSegments]
 * @param {number} [opt.heightSegments]
 */
var Plane_Plane = src_Geometry.extend(
/** @lends clay.geometry.Plane# */
{
    dynamic: false,
    /**
     * @type {number}
     */
    widthSegments: 1,
    /**
     * @type {number}
     */
    heightSegments: 1
}, function() {
    this.build();
},
/** @lends clay.geometry.Plane.prototype */
{
    /**
     * Build plane geometry
     */
    build: function() {
        var heightSegments = this.heightSegments;
        var widthSegments = this.widthSegments;
        var attributes = this.attributes;
        var positions = [];
        var texcoords = [];
        var normals = [];
        var faces = [];

        for (var y = 0; y <= heightSegments; y++) {
            var t = y / heightSegments;
            for (var x = 0; x <= widthSegments; x++) {
                var s = x / widthSegments;

                positions.push([2 * s - 1, 2 * t - 1, 0]);
                if (texcoords) {
                    texcoords.push([s, t]);
                }
                if (normals) {
                    normals.push([0, 0, 1]);
                }
                if (x < widthSegments && y < heightSegments) {
                    var i = x + y * (widthSegments + 1);
                    faces.push([i, i + 1, i + widthSegments + 1]);
                    faces.push([i + widthSegments + 1, i + 1, i + widthSegments + 2]);
                }
            }
        }

        attributes.position.fromArray(positions);
        attributes.texcoord0.fromArray(texcoords);
        attributes.normal.fromArray(normals);

        this.initIndicesFromArray(faces);

        this.boundingBox = new math_BoundingBox();
        this.boundingBox.min.set(-1, -1, 0);
        this.boundingBox.max.set(1, 1, 0);
    }
});

/* harmony default export */ const geometry_Plane = (Plane_Plane);

;// CONCATENATED MODULE: ./node_modules/claygl/src/geometry/Cube.js







var planeMatrix = new math_Matrix4();

/**
 * @constructor clay.geometry.Cube
 * @extends clay.Geometry
 * @param {Object} [opt]
 * @param {number} [opt.widthSegments]
 * @param {number} [opt.heightSegments]
 * @param {number} [opt.depthSegments]
 * @param {boolean} [opt.inside]
 */
var Cube = src_Geometry.extend(
/**@lends clay.geometry.Cube# */
{
    dynamic: false,
    /**
     * @type {number}
     */
    widthSegments: 1,
    /**
     * @type {number}
     */
    heightSegments: 1,
    /**
     * @type {number}
     */
    depthSegments: 1,
    /**
     * @type {boolean}
     */
    inside: false
}, function() {
    this.build();
},
/** @lends clay.geometry.Cube.prototype */
{
    /**
     * Build cube geometry
     */
    build: function() {

        var planes = {
            'px': createPlane('px', this.depthSegments, this.heightSegments),
            'nx': createPlane('nx', this.depthSegments, this.heightSegments),
            'py': createPlane('py', this.widthSegments, this.depthSegments),
            'ny': createPlane('ny', this.widthSegments, this.depthSegments),
            'pz': createPlane('pz', this.widthSegments, this.heightSegments),
            'nz': createPlane('nz', this.widthSegments, this.heightSegments),
        };

        var attrList = ['position', 'texcoord0', 'normal'];
        var vertexNumber = 0;
        var faceNumber = 0;
        for (var pos in planes) {
            vertexNumber += planes[pos].vertexCount;
            faceNumber += planes[pos].indices.length;
        }
        for (var k = 0; k < attrList.length; k++) {
            this.attributes[attrList[k]].init(vertexNumber);
        }
        this.indices = new core_vendor.Uint16Array(faceNumber);
        var faceOffset = 0;
        var vertexOffset = 0;
        for (var pos in planes) {
            var plane = planes[pos];
            for (var k = 0; k < attrList.length; k++) {
                var attrName = attrList[k];
                var attrArray = plane.attributes[attrName].value;
                var attrSize = plane.attributes[attrName].size;
                var isNormal = attrName === 'normal';
                for (var i = 0; i < attrArray.length; i++) {
                    var value = attrArray[i];
                    if (this.inside && isNormal) {
                        value = -value;
                    }
                    this.attributes[attrName].value[i + attrSize * vertexOffset] = value;
                }
            }
            var len = plane.indices.length;
            for (var i = 0; i < plane.indices.length; i++) {
                this.indices[i + faceOffset] = vertexOffset + plane.indices[this.inside ? (len - i - 1) : i];
            }
            faceOffset += plane.indices.length;
            vertexOffset += plane.vertexCount;
        }

        this.boundingBox = new math_BoundingBox();
        this.boundingBox.max.set(1, 1, 1);
        this.boundingBox.min.set(-1, -1, -1);
    }
});

function createPlane(pos, widthSegments, heightSegments) {

    planeMatrix.identity();

    var plane = new geometry_Plane({
        widthSegments: widthSegments,
        heightSegments: heightSegments
    });

    switch(pos) {
        case 'px':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.POSITIVE_X);
            math_Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI / 2);
            break;
        case 'nx':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.NEGATIVE_X);
            math_Matrix4.rotateY(planeMatrix, planeMatrix, -Math.PI / 2);
            break;
        case 'py':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.POSITIVE_Y);
            math_Matrix4.rotateX(planeMatrix, planeMatrix, -Math.PI / 2);
            break;
        case 'ny':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.NEGATIVE_Y);
            math_Matrix4.rotateX(planeMatrix, planeMatrix, Math.PI / 2);
            break;
        case 'pz':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.POSITIVE_Z);
            break;
        case 'nz':
            math_Matrix4.translate(planeMatrix, planeMatrix, math_Vector3.NEGATIVE_Z);
            math_Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI);
            break;
    }
    plane.applyTransform(planeMatrix);
    return plane;
}

/* harmony default export */ const geometry_Cube = (Cube);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/skybox.glsl.js
/* harmony default export */ const skybox_glsl = ("@export clay.skybox.vertex\n#define SHADER_NAME skybox\nuniform mat4 world : WORLD;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nvarying vec3 v_WorldPosition;\nvoid main()\n{\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n@export clay.skybox.fragment\n#define PI 3.1415926\nuniform mat4 viewInverse : VIEWINVERSE;\n#ifdef EQUIRECTANGULAR\nuniform sampler2D environmentMap;\n#else\nuniform samplerCube environmentMap;\n#endif\nuniform float lod: 0.0;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n#ifdef EQUIRECTANGULAR\n float phi = acos(V.y);\n float theta = atan(-V.x, V.z) + PI * 0.5;\n vec2 uv = vec2(theta / 2.0 / PI, phi / PI);\n vec4 texel = decodeHDR(texture2D(environmentMap, fract(uv)));\n#else\n #if defined(LOD) || defined(SUPPORT_TEXTURE_LOD)\n vec4 texel = decodeHDR(textureCubeLodEXT(environmentMap, V, lod));\n #else\n vec4 texel = decodeHDR(textureCube(environmentMap, V));\n #endif\n#endif\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#ifdef TONEMAPPING\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n#ifdef SRGB_ENCODE\n texel = linearTosRGB(texel);\n#endif\n gl_FragColor = encodeHDR(vec4(texel.rgb, 1.0));\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/plugin/Skybox.js
// TODO Should not derived from mesh?









src_Shader.import(skybox_glsl);
/**
 * @constructor clay.plugin.Skybox
 *
 * @example
 *     var skyTex = new clay.TextureCube();
 *     skyTex.load({
 *         'px': 'assets/textures/sky/px.jpg',
 *         'nx': 'assets/textures/sky/nx.jpg'
 *         'py': 'assets/textures/sky/py.jpg'
 *         'ny': 'assets/textures/sky/ny.jpg'
 *         'pz': 'assets/textures/sky/pz.jpg'
 *         'nz': 'assets/textures/sky/nz.jpg'
 *     });
 *     var skybox = new clay.plugin.Skybox({
 *         scene: scene
 *     });
 *     skybox.material.set('environmentMap', skyTex);
 */
var Skybox = src_Mesh.extend(function () {

    var skyboxShader = new src_Shader({
        vertex: src_Shader.source('clay.skybox.vertex'),
        fragment: src_Shader.source('clay.skybox.fragment')
    });
    var material = new src_Material({
        shader: skyboxShader,
        depthMask: false
    });

    return {
        /**
         * @type {clay.Scene}
         * @memberOf clay.plugin.Skybox.prototype
         */
        scene: null,

        geometry: new geometry_Cube(),

        material: material,

        environmentMap: null,

        culling: false,

        _dummyCamera: new camera_Perspective()
    };
}, function () {
    var scene = this.scene;
    if (scene) {
        this.attachScene(scene);
    }
    if (this.environmentMap) {
        this.setEnvironmentMap(this.environmentMap);
    }
}, /** @lends clay.plugin.Skybox# */ {
    /**
     * Attach the skybox to the scene
     * @param  {clay.Scene} scene
     */
    attachScene: function (scene) {
        if (this.scene) {
            this.detachScene();
        }
        scene.skybox = this;

        this.scene = scene;
        scene.on('beforerender', this._beforeRenderScene, this);
    },
    /**
     * Detach from scene
     */
    detachScene: function () {
        if (this.scene) {
            this.scene.off('beforerender', this._beforeRenderScene);
            this.scene.skybox = null;
        }
        this.scene = null;
    },

    /**
     * Dispose skybox
     * @param  {clay.Renderer} renderer
     */
    dispose: function (renderer) {
        this.detachScene();
        this.geometry.dispose(renderer);
    },
    /**
     * Set environment map
     * @param {clay.TextureCube} envMap
     */
    setEnvironmentMap: function (envMap) {
        if (envMap.textureType === 'texture2D') {
            this.material.define('EQUIRECTANGULAR');
            // LINEAR filter can remove the artifacts in pole
            envMap.minFilter = src_Texture.LINEAR;
        }
        else {
            this.material.undefine('EQUIRECTANGULAR');
        }
        this.material.set('environmentMap', envMap);
    },
    /**
     * Get environment map
     * @return {clay.TextureCube}
     */
    getEnvironmentMap: function () {
        return this.material.get('environmentMap');
    },

    _beforeRenderScene: function(renderer, scene, camera) {
        this.renderSkybox(renderer, camera);
    },

    renderSkybox: function (renderer, camera) {
        var dummyCamera = this._dummyCamera;
        dummyCamera.aspect = renderer.getViewportAspect();
        dummyCamera.fov = camera.fov || 50;
        dummyCamera.updateProjectionMatrix();
        math_Matrix4.invert(dummyCamera.invProjectionMatrix, dummyCamera.projectionMatrix);
        dummyCamera.worldTransform.copy(camera.worldTransform);
        dummyCamera.viewMatrix.copy(camera.viewMatrix);

        this.position.copy(camera.getWorldPosition());
        this.update();

        // Don't remember to disable blend
        renderer.gl.disable(renderer.gl.BLEND);
        if (this.material.get('lod') > 0) {
            this.material.define('fragment', 'LOD');
        }
        else {
            this.material.undefine('fragment', 'LOD');
        }
        renderer.renderPass([this], dummyCamera);
    }
});

/* harmony default export */ const plugin_Skybox = (Skybox);

;// CONCATENATED MODULE: ./node_modules/claygl/src/plugin/Skydome.js


/* harmony default export */ const Skydome = (plugin_Skybox);
;// CONCATENATED MODULE: ./node_modules/claygl/src/util/dds.js




// http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx
// https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js
var DDS_MAGIC = 0x20534444;

var DDSD_CAPS = 0x1;
var DDSD_HEIGHT = 0x2;
var DDSD_WIDTH = 0x4;
var DDSD_PITCH = 0x8;
var DDSD_PIXELFORMAT = 0x1000;
var DDSD_MIPMAPCOUNT = 0x20000;
var DDSD_LINEARSIZE = 0x80000;
var DDSD_DEPTH = 0x800000;

var DDSCAPS_COMPLEX = 0x8;
var DDSCAPS_MIPMAP = 0x400000;
var DDSCAPS_TEXTURE = 0x1000;

var DDSCAPS2_CUBEMAP = 0x200;
var DDSCAPS2_CUBEMAP_POSITIVEX = 0x400;
var DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800;
var DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000;
var DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000;
var DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000;
var DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000;
var DDSCAPS2_VOLUME = 0x200000;

var DDPF_ALPHAPIXELS = 0x1;
var DDPF_ALPHA = 0x2;
var DDPF_FOURCC = 0x4;
var DDPF_RGB = 0x40;
var DDPF_YUV = 0x200;
var DDPF_LUMINANCE = 0x20000;

function fourCCToInt32(value) {
    return value.charCodeAt(0) +
        (value.charCodeAt(1) << 8) +
        (value.charCodeAt(2) << 16) +
        (value.charCodeAt(3) << 24);
}

function int32ToFourCC(value) {
    return String.fromCharCode(
        value & 0xff,
        (value >> 8) & 0xff,
        (value >> 16) & 0xff,
        (value >> 24) & 0xff
    );
}

var headerLengthInt = 31; // The header length in 32 bit ints

var FOURCC_DXT1 = fourCCToInt32('DXT1');
var FOURCC_DXT3 = fourCCToInt32('DXT3');
var FOURCC_DXT5 = fourCCToInt32('DXT5');
// Offsets into the header array
var off_magic = 0;

var off_size = 1;
var off_flags = 2;
var off_height = 3;
var off_width = 4;

var off_mipmapCount = 7;

var off_pfFlags = 20;
var off_pfFourCC = 21;

var off_caps = 27;
var off_caps2 = 28;
var off_caps3 = 29;
var off_caps4 = 30;

var ret = {
    parse: function(arrayBuffer, out) {
        var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
        if (header[off_magic] !== DDS_MAGIC) {
            return null;
        }
        if (!header(off_pfFlags) & DDPF_FOURCC) {
            return null;
        }

        var fourCC = header(off_pfFourCC);
        var width = header[off_width];
        var height = header[off_height];
        var isCubeMap = header[off_caps2] & DDSCAPS2_CUBEMAP;
        var hasMipmap = header[off_flags] & DDSD_MIPMAPCOUNT;
        var blockBytes, internalFormat;
        switch(fourCC) {
            case FOURCC_DXT1:
                blockBytes = 8;
                internalFormat = src_Texture.COMPRESSED_RGB_S3TC_DXT1_EXT;
                break;
            case FOURCC_DXT3:
                blockBytes = 16;
                internalFormat = src_Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT;
                break;
            case FOURCC_DXT5:
                blockBytes = 16;
                internalFormat = src_Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT;
                break;
            default:
                return null;
        }
        var dataOffset = header[off_size] + 4;
        // TODO: Suppose all face are existed
        var faceNumber = isCubeMap ? 6 : 1;
        var mipmapCount = 1;
        if (hasMipmap) {
            mipmapCount = Math.max(1, header[off_mipmapCount]);
        }

        var textures = [];
        for (var f = 0; f < faceNumber; f++) {
            var _width = width;
            var _height = height;
            textures[f] = new src_Texture2D({
                width: _width,
                height: _height,
                format: internalFormat
            });
            var mipmaps = [];
            for (var i = 0; i < mipmapCount; i++) {
                var dataLength = Math.max(4, _width) / 4 * Math.max(4, _height) / 4 * blockBytes;
                var byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength);

                dataOffset += dataLength;
                _width *= 0.5;
                _height *= 0.5;
                mipmaps[i] = byteArray;
            }
            textures[f].pixels = mipmaps[0];
            if (hasMipmap) {
                textures[f].mipmaps = mipmaps;
            }
        }
        // TODO
        // return isCubeMap ? textures : textures[0];
        if (out) {
            out.width = textures[0].width;
            out.height = textures[0].height;
            out.format = textures[0].format;
            out.pixels = textures[0].pixels;
            out.mipmaps = textures[0].mipmaps;
        }
        else {
            return textures[0];
        }
    }
};

/* harmony default export */ const dds = (ret);

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/hdr.js


var toChar = String.fromCharCode;

var MINELEN = 8;
var MAXELEN = 0x7fff;
function rgbe2float(rgbe, buffer, offset, exposure) {
    if (rgbe[3] > 0) {
        var f = Math.pow(2.0, rgbe[3] - 128 - 8 + exposure);
        buffer[offset + 0] = rgbe[0] * f;
        buffer[offset + 1] = rgbe[1] * f;
        buffer[offset + 2] = rgbe[2] * f;
    }
    else {
        buffer[offset + 0] = 0;
        buffer[offset + 1] = 0;
        buffer[offset + 2] = 0;
    }
    buffer[offset + 3] = 1.0;
    return buffer;
}

function uint82string(array, offset, size) {
    var str = '';
    for (var i = offset; i < size; i++) {
        str += toChar(array[i]);
    }
    return str;
}

function copyrgbe(s, t) {
    t[0] = s[0];
    t[1] = s[1];
    t[2] = s[2];
    t[3] = s[3];
}

// TODO : check
function oldReadColors(scan, buffer, offset, xmax) {
    var rshift = 0, x = 0, len = xmax;
    while (len > 0) {
        scan[x][0] = buffer[offset++];
        scan[x][1] = buffer[offset++];
        scan[x][2] = buffer[offset++];
        scan[x][3] = buffer[offset++];
        if (scan[x][0] === 1 && scan[x][1] === 1 && scan[x][2] === 1) {
            // exp is count of repeated pixels
            for (var i = (scan[x][3] << rshift) >>> 0; i > 0; i--) {
                copyrgbe(scan[x-1], scan[x]);
                x++;
                len--;
            }
            rshift += 8;
        } else {
            x++;
            len--;
            rshift = 0;
        }
    }
    return offset;
}

function readColors(scan, buffer, offset, xmax) {
    if ((xmax < MINELEN) | (xmax > MAXELEN)) {
        return oldReadColors(scan, buffer, offset, xmax);
    }
    var i = buffer[offset++];
    if (i != 2) {
        return oldReadColors(scan, buffer, offset - 1, xmax);
    }
    scan[0][1] = buffer[offset++];
    scan[0][2] = buffer[offset++];

    i = buffer[offset++];
    if ((((scan[0][2] << 8) >>> 0) | i) >>> 0 !== xmax) {
        return null;
    }
    for (var i = 0; i < 4; i++) {
        for (var x = 0; x < xmax;) {
            var code = buffer[offset++];
            if (code > 128) {
                code = (code & 127) >>> 0;
                var val = buffer[offset++];
                while (code--) {
                    scan[x++][i] = val;
                }
            } else {
                while (code--) {
                    scan[x++][i] = buffer[offset++];
                }
            }
        }
    }
    return offset;
}


var hdr_ret = {
    // http://www.graphics.cornell.edu/~bjw/rgbe.html
    // Blender source
    // http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html
    parseRGBE: function(arrayBuffer, texture, exposure) {
        if (exposure == null) {
            exposure = 0;
        }
        var data = new Uint8Array(arrayBuffer);
        var size = data.length;
        if (uint82string(data, 0, 2) !== '#?') {
            return;
        }
        // find empty line, next line is resolution info
        for (var i = 2; i < size; i++) {
            if (toChar(data[i]) === '\n' && toChar(data[i+1]) === '\n') {
                break;
            }
        }
        if (i >= size) { // not found
            return;
        }
        // find resolution info line
        i += 2;
        var str = '';
        for (; i < size; i++) {
            var _char = toChar(data[i]);
            if (_char === '\n') {
                break;
            }
            str += _char;
        }
        // -Y M +X N
        var tmp = str.split(' ');
        var height = parseInt(tmp[1]);
        var width = parseInt(tmp[3]);
        if (!width || !height) {
            return;
        }

        // read and decode actual data
        var offset = i+1;
        var scanline = [];
        // memzero
        for (var x = 0; x < width; x++) {
            scanline[x] = [];
            for (var j = 0; j < 4; j++) {
                scanline[x][j] = 0;
            }
        }
        var pixels = new Float32Array(width * height * 4);
        var offset2 = 0;
        for (var y = 0; y < height; y++) {
            var offset = readColors(scanline, data, offset, width);
            if (!offset) {
                return null;
            }
            for (var x = 0; x < width; x++) {
                rgbe2float(scanline[x], pixels, offset2, exposure);
                offset2 += 4;
            }
        }

        if (!texture) {
            texture = new src_Texture2D();
        }
        texture.width = width;
        texture.height = height;
        texture.pixels = pixels;
        // HALF_FLOAT can't use Float32Array
        texture.type = src_Texture.FLOAT;
        return texture;
    },

    parseRGBEFromPNG: function(png) {

    }
};

/* harmony default export */ const hdr = (hdr_ret);

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/texture.js










/**
 * @alias clay.util.texture
 */
var textureUtil = {
    /**
     * @param  {string|object} path
     * @param  {object} [option]
     * @param  {Function} [onsuccess]
     * @param  {Function} [onerror]
     * @return {clay.Texture}
     */
    loadTexture: function (path, option, onsuccess, onerror) {
        var texture;
        if (typeof(option) === 'function') {
            onsuccess = option;
            onerror = onsuccess;
            option = {};
        }
        else {
            option = option || {};
        }
        if (typeof(path) === 'string') {
            if (path.match(/.hdr$/) || option.fileType === 'hdr') {
                texture = new src_Texture2D({
                    width: 0,
                    height: 0,
                    sRGB: false
                });
                textureUtil._fetchTexture(
                    path,
                    function (data) {
                        hdr.parseRGBE(data, texture, option.exposure);
                        texture.dirty();
                        onsuccess && onsuccess(texture);
                    },
                    onerror
                );
                return texture;
            }
            else if (path.match(/.dds$/) || option.fileType === 'dds') {
                texture = new src_Texture2D({
                    width: 0,
                    height: 0
                });
                textureUtil._fetchTexture(
                    path,
                    function (data) {
                        dds.parse(data, texture);
                        texture.dirty();
                        onsuccess && onsuccess(texture);
                    },
                    onerror
                );
            }
            else {
                texture = new src_Texture2D();
                texture.load(path);
                texture.success(onsuccess);
                texture.error(onerror);
            }
        }
        else if (typeof path === 'object' && typeof(path.px) !== 'undefined') {
            texture = new src_TextureCube();
            texture.load(path);
            texture.success(onsuccess);
            texture.error(onerror);
        }
        return texture;
    },

    /**
     * Load a panorama texture and render it to a cube map
     * @param  {clay.Renderer} renderer
     * @param  {string} path
     * @param  {clay.TextureCube} cubeMap
     * @param  {object} [option]
     * @param  {boolean} [option.encodeRGBM]
     * @param  {number} [option.exposure]
     * @param  {Function} [onsuccess]
     * @param  {Function} [onerror]
     */
    loadPanorama: function (renderer, path, cubeMap, option, onsuccess, onerror) {
        var self = this;

        if (typeof(option) === 'function') {
            onsuccess = option;
            onerror = onsuccess;
            option = {};
        }
        else {
            option = option || {};
        }

        textureUtil.loadTexture(path, option, function (texture) {
            // PENDING
            texture.flipY = option.flipY || false;
            self.panoramaToCubeMap(renderer, texture, cubeMap, option);
            texture.dispose(renderer);
            onsuccess && onsuccess(cubeMap);
        }, onerror);
    },

    /**
     * Render a panorama texture to a cube map
     * @param  {clay.Renderer} renderer
     * @param  {clay.Texture2D} panoramaMap
     * @param  {clay.TextureCube} cubeMap
     * @param  {Object} option
     * @param  {boolean} [option.encodeRGBM]
     */
    panoramaToCubeMap: function (renderer, panoramaMap, cubeMap, option) {
        var environmentMapPass = new EnvironmentMap();
        var skydome = new Skydome({
            scene: new src_Scene()
        });
        skydome.setEnvironmentMap(panoramaMap);

        option = option || {};
        if (option.encodeRGBM) {
            skydome.material.define('fragment', 'RGBM_ENCODE');
        }

        // Share sRGB
        cubeMap.sRGB = panoramaMap.sRGB;

        environmentMapPass.texture = cubeMap;
        environmentMapPass.render(renderer, skydome.scene);
        environmentMapPass.texture = null;
        environmentMapPass.dispose(renderer);
        return cubeMap;
    },

    /**
     * Convert height map to normal map
     * @param {HTMLImageElement|HTMLCanvasElement} image
     * @param {boolean} [checkBump=false]
     * @return {HTMLCanvasElement}
     */
    heightToNormal: function (image, checkBump) {
        var canvas = document.createElement('canvas');
        var width = canvas.width = image.width;
        var height = canvas.height = image.height;
        var ctx = canvas.getContext('2d');
        ctx.drawImage(image, 0, 0, width, height);
        checkBump = checkBump || false;
        var srcData = ctx.getImageData(0, 0, width, height);
        var dstData = ctx.createImageData(width, height);
        for (var i = 0; i < srcData.data.length; i += 4) {
            if (checkBump) {
                var r = srcData.data[i];
                var g = srcData.data[i + 1];
                var b = srcData.data[i + 2];
                var diff = Math.abs(r - g) + Math.abs(g - b);
                if (diff > 20) {
                    console.warn('Given image is not a height map');
                    return image;
                }
            }
            // Modified from http://mrdoob.com/lab/javascript/height2normal/
            var x1, y1, x2, y2;
            if (i % (width * 4) === 0) {
                // left edge
                x1 = srcData.data[i];
                x2 = srcData.data[i + 4];
            }
            else if (i % (width * 4) === (width - 1) * 4) {
                // right edge
                x1 = srcData.data[i - 4];
                x2 = srcData.data[i];
            }
            else {
                x1 = srcData.data[i - 4];
                x2 = srcData.data[i + 4];
            }

            if (i < width * 4) {
                // top edge
                y1 = srcData.data[i];
                y2 = srcData.data[i + width * 4];
            }
            else if (i > width * (height - 1) * 4) {
                // bottom edge
                y1 = srcData.data[i - width * 4];
                y2 = srcData.data[i];
            }
            else {
                y1 = srcData.data[i - width * 4];
                y2 = srcData.data[i + width * 4];
            }

            dstData.data[i] = (x1 - x2) + 127;
            dstData.data[i + 1] = (y1 - y2) + 127;
            dstData.data[i + 2] = 255;
            dstData.data[i + 3] = 255;
        }
        ctx.putImageData(dstData, 0, 0);
        return canvas;
    },

    /**
     * Convert height map to normal map
     * @param {HTMLImageElement|HTMLCanvasElement} image
     * @param {boolean} [checkBump=false]
     * @param {number} [threshold=20]
     * @return {HTMLCanvasElement}
     */
    isHeightImage: function (img, downScaleSize, threshold) {
        if (!img || !img.width || !img.height) {
            return false;
        }

        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        var size = downScaleSize || 32;
        threshold = threshold || 20;
        canvas.width = canvas.height = size;
        ctx.drawImage(img, 0, 0, size, size);
        var srcData = ctx.getImageData(0, 0, size, size);
        for (var i = 0; i < srcData.data.length; i += 4) {
            var r = srcData.data[i];
            var g = srcData.data[i + 1];
            var b = srcData.data[i + 2];
            var diff = Math.abs(r - g) + Math.abs(g - b);
            if (diff > threshold) {
                return false;
            }
        }
        return true;
    },

    _fetchTexture: function (path, onsuccess, onerror) {
        core_vendor.request.get({
            url: path,
            responseType: 'arraybuffer',
            onload: onsuccess,
            onerror: onerror
        });
    },

    /**
     * Create a chessboard texture
     * @param  {number} [size]
     * @param  {number} [unitSize]
     * @param  {string} [color1]
     * @param  {string} [color2]
     * @return {clay.Texture2D}
     */
    createChessboard: function (size, unitSize, color1, color2) {
        size = size || 512;
        unitSize = unitSize || 64;
        color1 = color1 || 'black';
        color2 = color2 || 'white';

        var repeat = Math.ceil(size / unitSize);

        var canvas = document.createElement('canvas');
        canvas.width = size;
        canvas.height = size;
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = color2;
        ctx.fillRect(0, 0, size, size);

        ctx.fillStyle = color1;
        for (var i = 0; i < repeat; i++) {
            for (var j = 0; j < repeat; j++) {
                var isFill = j % 2 ? (i % 2) : (i % 2 - 1);
                if (isFill) {
                    ctx.fillRect(i * unitSize, j * unitSize, unitSize, unitSize);
                }
            }
        }

        var texture = new src_Texture2D({
            image: canvas,
            anisotropic: 8
        });

        return texture;
    },

    /**
     * Create a blank pure color 1x1 texture
     * @param  {string} color
     * @return {clay.Texture2D}
     */
    createBlank: function (color) {
        var canvas = document.createElement('canvas');
        canvas.width = 1;
        canvas.height = 1;
        var ctx = canvas.getContext('2d');
        ctx.fillStyle = color;
        ctx.fillRect(0, 0, 1, 1);

        var texture = new src_Texture2D({
            image: canvas
        });

        return texture;
    }
};

/* harmony default export */ const util_texture = (textureUtil);

;// CONCATENATED MODULE: ./src/util/EChartsSurface.js
/**
 * Surface texture in the 3D scene.
 * Provide management and rendering of zrender shapes and groups
 *
 * @module echarts-gl/util/EChartsSurface
 * @author Yi Shen(http://github.com/pissang)
 */





var events = ['mousedown', 'mouseup', 'mousemove', 'mouseover', 'mouseout', 'click', 'dblclick', 'contextmenu'];

function makeHandlerName(eventName) {
    return '_on' + eventName;
}
/**
 * @constructor
 * @alias echarts-gl/util/EChartsSurface
 * @param {module:echarts~ECharts} chart
 */
var EChartsSurface = function (chart) {
    var self = this;
    this._texture = new src_Texture2D({
        anisotropic: 32,
        flipY: false,

        surface: this,

        dispose: function (renderer) {
            self.dispose();
            src_Texture2D.prototype.dispose.call(this, renderer);
        }
    });

    events.forEach(function (eventName) {
        this[makeHandlerName(eventName)] = function (eveObj) {
            if (!eveObj.triangle) {
                return;
            }
            this._meshes.forEach(function (mesh) {
                this.dispatchEvent(eventName, mesh, eveObj.triangle, eveObj.point);
            }, this);
        };
    }, this);

    this._meshes = [];

    if (chart) {
        this.setECharts(chart);
    }

    // Texture updated callback;
    this.onupdate = null;
};

EChartsSurface.prototype = {

    constructor: EChartsSurface,

    getTexture: function () {
        return this._texture;
    },

    setECharts: function (chart) {
        this._chart = chart;

        var canvas = chart.getDom();
        if (!(canvas instanceof HTMLCanvasElement)) {
            console.error('ECharts must init on canvas if it is used as texture.');
            // Use an empty canvas
            canvas = document.createElement('canvas');
        }
        else {
            var self = this;
            // Wrap refreshImmediately
            var zr = chart.getZr();
            var oldRefreshImmediately = zr.__oldRefreshImmediately || zr.refreshImmediately;
            zr.refreshImmediately = function () {
                oldRefreshImmediately.call(this);
                self._texture.dirty();

                self.onupdate && self.onupdate();
            };
            zr.__oldRefreshImmediately = oldRefreshImmediately;
        }

        this._texture.image = canvas;
        this._texture.dirty();
        this.onupdate && this.onupdate();
    },

    /**
     * @method
     * @param {clay.Mesh} attachedMesh
     * @param {Array.<number>} triangle Triangle indices
     * @param {clay.math.Vector3} point
     */
    dispatchEvent: (function () {

        var p0 = new math_Vector3();
        var p1 = new math_Vector3();
        var p2 = new math_Vector3();
        var uv0 = new math_Vector2();
        var uv1 = new math_Vector2();
        var uv2 = new math_Vector2();
        var uv = new math_Vector2();

        var vCross = new math_Vector3();

        return function (eventName, attachedMesh, triangle, point) {
            var geo = attachedMesh.geometry;
            var position = geo.attributes.position;
            var texcoord = geo.attributes.texcoord0;
            var dot = math_Vector3.dot;
            var cross = math_Vector3.cross;

            position.get(triangle[0], p0.array);
            position.get(triangle[1], p1.array);
            position.get(triangle[2], p2.array);
            texcoord.get(triangle[0], uv0.array);
            texcoord.get(triangle[1], uv1.array);
            texcoord.get(triangle[2], uv2.array);

            cross(vCross, p1, p2);
            var det = dot(p0, vCross);
            var t = dot(point, vCross) / det;
            cross(vCross, p2, p0);
            var u = dot(point, vCross) / det;
            cross(vCross, p0, p1);
            var v = dot(point, vCross) / det;

            math_Vector2.scale(uv, uv0, t);
            math_Vector2.scaleAndAdd(uv, uv, uv1, u);
            math_Vector2.scaleAndAdd(uv, uv, uv2, v);

            var x = uv.x * this._chart.getWidth();
            var y = uv.y * this._chart.getHeight();
            this._chart.getZr().handler.dispatch(eventName, {
                zrX: x,
                zrY: y
            });
        };
    })(),

    attachToMesh: function (mesh) {
        if (this._meshes.indexOf(mesh) >= 0) {
            return;
        }

        events.forEach(function (eventName) {
            mesh.on(eventName, this[makeHandlerName(eventName)], this);
        }, this);

        this._meshes.push(mesh);
    },

    detachFromMesh: function (mesh) {
        var idx = this._meshes.indexOf(mesh);
        if (idx >= 0) {
            this._meshes.splice(idx, 1);
        }

        events.forEach(function (eventName) {
            mesh.off(eventName, this[makeHandlerName(eventName)]);
        }, this);
    },

    dispose: function () {
        this._meshes.forEach(function (mesh) {
            this.detachFromMesh(mesh);
        }, this);
    }
};

/* harmony default export */ const util_EChartsSurface = (EChartsSurface);
;// CONCATENATED MODULE: ./node_modules/claygl/src/camera/Orthographic.js

/**
 * @constructor clay.camera.Orthographic
 * @extends clay.Camera
 */
var Orthographic = src_Camera.extend(
/** @lends clay.camera.Orthographic# */
{
    /**
     * @type {number}
     */
    left: -1,
    /**
     * @type {number}
     */
    right: 1,
    /**
     * @type {number}
     */
    near: -1,
    /**
     * @type {number}
     */
    far: 1,
    /**
     * @type {number}
     */
    top: 1,
    /**
     * @type {number}
     */
    bottom: -1
},
/** @lends clay.camera.Orthographic.prototype */
{

    updateProjectionMatrix: function() {
        this.projectionMatrix.ortho(this.left, this.right, this.bottom, this.top, this.near, this.far);
    },

    decomposeProjectionMatrix: function () {
        var m = this.projectionMatrix.array;
        this.left = (-1 - m[12]) / m[0];
        this.right = (1 - m[12]) / m[0];
        this.top = (1 - m[13]) / m[5];
        this.bottom = (-1 - m[13]) / m[5];
        this.near = -(-1 - m[14]) / m[10];
        this.far = -(1 - m[14]) / m[10];
    },
    /**
     * @return {clay.camera.Orthographic}
     */
    clone: function() {
        var camera = src_Camera.prototype.clone.call(this);
        camera.left = this.left;
        camera.right = this.right;
        camera.near = this.near;
        camera.far = this.far;
        camera.top = this.top;
        camera.bottom = this.bottom;

        return camera;
    }
});

/* harmony default export */ const camera_Orthographic = (Orthographic);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/vertex.glsl.js
/* harmony default export */ const vertex_glsl = ("\n@export clay.compositor.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n v_Texcoord = texcoord;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/Pass.js









src_Shader.import(vertex_glsl);

var planeGeo = new geometry_Plane();
var mesh = new src_Mesh({
    geometry: planeGeo,
    frustumCulling: false
});
var camera = new camera_Orthographic();

/**
 * @constructor clay.compositor.Pass
 * @extends clay.core.Base
 */
var Pass = core_Base.extend(function () {
    return /** @lends clay.compositor.Pass# */ {
        /**
         * Fragment shader string
         * @type {string}
         */
        // PENDING shader or fragment ?
        fragment: '',

        /**
         * @type {Object}
         */
        outputs: null,

        /**
         * @type {clay.Material}
         */
        material: null,

        /**
         * @type {Boolean}
         */
        blendWithPrevious: false,

        /**
         * @type {Boolean}
         */
        clearColor: false,

        /**
         * @type {Boolean}
         */
        clearDepth: true
    };
}, function() {

    var shader = new src_Shader(src_Shader.source('clay.compositor.vertex'), this.fragment);
    var material = new src_Material({
        shader: shader
    });
    material.enableTexturesAll();

    this.material = material;

},
/** @lends clay.compositor.Pass.prototype */
{
    /**
     * @param {string} name
     * @param {} value
     */
    setUniform: function(name, value) {
        this.material.setUniform(name, value);
    },
    /**
     * @param  {string} name
     * @return {}
     */
    getUniform: function(name) {
        var uniform = this.material.uniforms[name];
        if (uniform) {
            return uniform.value;
        }
    },
    /**
     * @param  {clay.Texture} texture
     * @param  {number} attachment
     */
    attachOutput: function(texture, attachment) {
        if (!this.outputs) {
            this.outputs = {};
        }
        attachment = attachment || glenum.COLOR_ATTACHMENT0;
        this.outputs[attachment] = texture;
    },
    /**
     * @param  {clay.Texture} texture
     */
    detachOutput: function(texture) {
        for (var attachment in this.outputs) {
            if (this.outputs[attachment] === texture) {
                this.outputs[attachment] = null;
            }
        }
    },

    bind: function(renderer, frameBuffer) {

        if (this.outputs) {
            for (var attachment in this.outputs) {
                var texture = this.outputs[attachment];
                if (texture) {
                    frameBuffer.attach(texture, attachment);
                }
            }
        }

        if (frameBuffer) {
            frameBuffer.bind(renderer);
        }
    },

    unbind: function(renderer, frameBuffer) {
        frameBuffer.unbind(renderer);
    },
    /**
     * @param  {clay.Renderer} renderer
     * @param  {clay.FrameBuffer} [frameBuffer]
     */
    render: function(renderer, frameBuffer) {

        var _gl = renderer.gl;

        if (frameBuffer) {
            this.bind(renderer, frameBuffer);
            // MRT Support in chrome
            // https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/ext-draw-buffers.html
            var ext = renderer.getGLExtension('EXT_draw_buffers');
            if (ext && this.outputs) {
                var bufs = [];
                for (var attachment in this.outputs) {
                    attachment = +attachment;
                    if (attachment >= _gl.COLOR_ATTACHMENT0 && attachment <= _gl.COLOR_ATTACHMENT0 + 8) {
                        bufs.push(attachment);
                    }
                }
                ext.drawBuffersEXT(bufs);
            }
        }

        this.trigger('beforerender', this, renderer);

        // FIXME Don't clear in each pass in default, let the color overwrite the buffer
        // FIXME pixels may be discard
        var clearBit = this.clearDepth ? _gl.DEPTH_BUFFER_BIT : 0;
        _gl.depthMask(true);
        if (this.clearColor) {
            clearBit = clearBit | _gl.COLOR_BUFFER_BIT;
            _gl.colorMask(true, true, true, true);
            var cc = this.clearColor;
            if (Array.isArray(cc)) {
                _gl.clearColor(cc[0], cc[1], cc[2], cc[3]);
            }
        }
        _gl.clear(clearBit);

        if (this.blendWithPrevious) {
            // Blend with previous rendered scene in the final output
            // FIXME Configure blend.
            // FIXME It will cause screen blink？
            _gl.enable(_gl.BLEND);
            this.material.transparent = true;
        }
        else {
            _gl.disable(_gl.BLEND);
            this.material.transparent = false;
        }

        this.renderQuad(renderer);

        this.trigger('afterrender', this, renderer);

        if (frameBuffer) {
            this.unbind(renderer, frameBuffer);
        }
    },

    /**
     * Simply do quad rendering
     */
    renderQuad: function (renderer) {
        mesh.material = this.material;
        renderer.renderPass([mesh], camera);
    },

    /**
     * @param  {clay.Renderer} renderer
     */
    dispose: function (renderer) {}
});

/* harmony default export */ const compositor_Pass = (Pass);

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/shader/integrateBRDF.glsl.js
/* harmony default export */ const integrateBRDF_glsl = ("#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform sampler2D normalDistribution;\nuniform vec2 viewportSize : [512, 256];\nconst vec3 N = vec3(0.0, 0.0, 1.0);\nconst float fSampleNumber = float(SAMPLE_NUMBER);\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nfloat G_Smith(float roughness, float NoV, float NoL) {\n float k = roughness * roughness / 2.0;\n float G1V = NoV / (NoV * (1.0 - k) + k);\n float G1L = NoL / (NoL * (1.0 - k) + k);\n return G1L * G1V;\n}\nvoid main() {\n vec2 uv = gl_FragCoord.xy / viewportSize;\n float NoV = uv.x;\n float roughness = uv.y;\n vec3 V;\n V.x = sqrt(1.0 - NoV * NoV);\n V.y = 0.0;\n V.z = NoV;\n float A = 0.0;\n float B = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(L.z, 0.0, 1.0);\n float NoH = clamp(H.z, 0.0, 1.0);\n float VoH = clamp(dot(V, H), 0.0, 1.0);\n if (NoL > 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n");

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/shader/prefilter.glsl.js
/* harmony default export */ const prefilter_glsl = ("#define SHADER_NAME prefilter\n#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform sampler2D normalDistribution;\nuniform float roughness : 0.5;\nvarying vec2 v_Texcoord;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvoid main() {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n vec3 N = V;\n vec3 prefilteredColor = vec3(0.0);\n float totalWeight = 0.0;\n float fMaxSampleNumber = float(SAMPLE_NUMBER);\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fMaxSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(dot(N, L), 0.0, 1.0);\n if (NoL > 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n");

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/cubemap.js
// Cubemap prefilter utility
// http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf
// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html
















var cubemapUtil = {};

var cubemap_targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz'];

// TODO Downsample
/**
 * @name clay.util.cubemap.prefilterEnvironmentMap
 * @param  {clay.Renderer} renderer
 * @param  {clay.Texture} envMap
 * @param  {Object} [textureOpts]
 * @param  {number} [textureOpts.width=64]
 * @param  {number} [textureOpts.height=64]
 * @param  {number} [textureOpts.type]
 * @param  {boolean} [textureOpts.encodeRGBM=false]
 * @param  {boolean} [textureOpts.decodeRGBM=false]
 * @param  {clay.Texture2D} [normalDistribution]
 * @param  {clay.Texture2D} [brdfLookup]
 */
cubemapUtil.prefilterEnvironmentMap = function (
    renderer, envMap, textureOpts, normalDistribution, brdfLookup
) {
    // Not create other renderer, it is easy having issue of cross reference of resources like framebuffer
    // PENDING preserveDrawingBuffer?
    if (!brdfLookup || !normalDistribution) {
        normalDistribution = cubemapUtil.generateNormalDistribution();
        brdfLookup = cubemapUtil.integrateBRDF(renderer, normalDistribution);
    }
    textureOpts = textureOpts || {};

    var width = textureOpts.width || 64;
    var height = textureOpts.height || 64;

    var textureType = textureOpts.type || envMap.type;

    // Use same type with given envMap
    var prefilteredCubeMap = new src_TextureCube({
        width: width,
        height: height,
        type: textureType,
        flipY: false,
        mipmaps: []
    });

    if (!prefilteredCubeMap.isPowerOfTwo()) {
        console.warn('Width and height must be power of two to enable mipmap.');
    }

    var size = Math.min(width, height);
    var mipmapNum = Math.log(size) / Math.log(2) + 1;

    var prefilterMaterial = new src_Material({
        shader: new src_Shader({
            vertex: src_Shader.source('clay.skybox.vertex'),
            fragment: prefilter_glsl
        })
    });
    prefilterMaterial.set('normalDistribution', normalDistribution);

    textureOpts.encodeRGBM && prefilterMaterial.define('fragment', 'RGBM_ENCODE');
    textureOpts.decodeRGBM && prefilterMaterial.define('fragment', 'RGBM_DECODE');

    var dummyScene = new src_Scene();
    var skyEnv;

    if (envMap.textureType === 'texture2D') {
        // Convert panorama to cubemap
        var envCubemap = new src_TextureCube({
            width: width,
            height: height,
            // FIXME FLOAT type will cause GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error on iOS
            type: textureType === src_Texture.FLOAT ?
                src_Texture.HALF_FLOAT : textureType
        });
        util_texture.panoramaToCubeMap(renderer, envMap, envCubemap, {
            // PENDING encodeRGBM so it can be decoded as RGBM
            encodeRGBM: textureOpts.decodeRGBM
        });
        envMap = envCubemap;
    }
    skyEnv = new plugin_Skybox({
        scene: dummyScene,
        material: prefilterMaterial
    });
    skyEnv.material.set('environmentMap', envMap);

    var envMapPass = new EnvironmentMap({
        texture: prefilteredCubeMap
    });

    // Force to be UNSIGNED_BYTE
    if (textureOpts.encodeRGBM) {
        textureType = prefilteredCubeMap.type = src_Texture.UNSIGNED_BYTE;
    }

    var renderTargetTmp = new src_Texture2D({
        width: width,
        height: height,
        type: textureType
    });
    var frameBuffer = new src_FrameBuffer({
        depthBuffer: false
    });
    var ArrayCtor = core_vendor[textureType === src_Texture.UNSIGNED_BYTE ? 'Uint8Array' : 'Float32Array'];
    for (var i = 0; i < mipmapNum; i++) {
        // console.time('prefilter');
        prefilteredCubeMap.mipmaps[i] = {
            pixels: {}
        };
        skyEnv.material.set('roughness', i / (mipmapNum - 1));

        // Tweak fov
        // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/
        var n = renderTargetTmp.width;
        var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180;

        for (var j = 0; j < cubemap_targets.length; j++) {
            var pixels = new ArrayCtor(renderTargetTmp.width * renderTargetTmp.height * 4);
            frameBuffer.attach(renderTargetTmp);
            frameBuffer.bind(renderer);

            var camera = envMapPass.getCamera(cubemap_targets[j]);
            camera.fov = fov;
            renderer.render(dummyScene, camera);
            renderer.gl.readPixels(
                0, 0, renderTargetTmp.width, renderTargetTmp.height,
                src_Texture.RGBA, textureType, pixels
            );

            // var canvas = document.createElement('canvas');
            // var ctx = canvas.getContext('2d');
            // canvas.width = renderTargetTmp.width;
            // canvas.height = renderTargetTmp.height;
            // var imageData = ctx.createImageData(renderTargetTmp.width, renderTargetTmp.height);
            // for (var k = 0; k < pixels.length; k++) {
            //     imageData.data[k] = pixels[k];
            // }
            // ctx.putImageData(imageData, 0, 0);
            // document.body.appendChild(canvas);

            frameBuffer.unbind(renderer);
            prefilteredCubeMap.mipmaps[i].pixels[cubemap_targets[j]] = pixels;
        }

        renderTargetTmp.width /= 2;
        renderTargetTmp.height /= 2;
        renderTargetTmp.dirty();
        // console.timeEnd('prefilter');
    }

    frameBuffer.dispose(renderer);
    renderTargetTmp.dispose(renderer);
    skyEnv.dispose(renderer);
    // Remove gpu resource allucated in renderer
    normalDistribution.dispose(renderer);

    // renderer.dispose();

    return {
        environmentMap: prefilteredCubeMap,
        brdfLookup: brdfLookup,
        normalDistribution: normalDistribution,
        maxMipmapLevel: mipmapNum
    };
};

cubemapUtil.integrateBRDF = function (renderer, normalDistribution) {
    normalDistribution = normalDistribution || cubemapUtil.generateNormalDistribution();
    var framebuffer = new src_FrameBuffer({
        depthBuffer: false
    });
    var pass = new compositor_Pass({
        fragment: integrateBRDF_glsl
    });

    var texture = new src_Texture2D({
        width: 512,
        height: 256,
        type: src_Texture.HALF_FLOAT,
        wrapS: src_Texture.CLAMP_TO_EDGE,
        wrapT: src_Texture.CLAMP_TO_EDGE,
        minFilter: src_Texture.NEAREST,
        magFilter: src_Texture.NEAREST,
        useMipmap: false
    });
    pass.setUniform('normalDistribution', normalDistribution);
    pass.setUniform('viewportSize', [512, 256]);
    pass.attachOutput(texture);
    pass.render(renderer, framebuffer);

    // FIXME Only chrome and firefox can readPixels with float type.
    // framebuffer.bind(renderer);
    // var pixels = new Float32Array(512 * 256 * 4);
    // renderer.gl.readPixels(
    //     0, 0, texture.width, texture.height,
    //     Texture.RGBA, Texture.FLOAT, pixels
    // );
    // texture.pixels = pixels;
    // texture.flipY = false;
    // texture.dirty();
    // framebuffer.unbind(renderer);

    framebuffer.dispose(renderer);

    return texture;
};

cubemapUtil.generateNormalDistribution = function (roughnessLevels, sampleSize) {

    // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
    // GLSL not support bit operation, use lookup instead
    // V -> i / N, U -> roughness
    var roughnessLevels = roughnessLevels || 256;
    var sampleSize = sampleSize || 1024;

    var normalDistribution = new src_Texture2D({
        width: roughnessLevels,
        height: sampleSize,
        type: src_Texture.FLOAT,
        minFilter: src_Texture.NEAREST,
        magFilter: src_Texture.NEAREST,
        wrapS: src_Texture.CLAMP_TO_EDGE,
        wrapT: src_Texture.CLAMP_TO_EDGE,
        useMipmap: false
    });
    var pixels = new Float32Array(sampleSize * roughnessLevels * 4);
    var tmp = [];

    // function sortFunc(a, b) {
    //     return Math.abs(b) - Math.abs(a);
    // }
    for (var j = 0; j < roughnessLevels; j++) {
        var roughness = j / roughnessLevels;
        var a = roughness * roughness;

        for (var i = 0; i < sampleSize; i++) {
            // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
            // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators
            // http://stackoverflow.com/questions/1908492/unsigned-integer-in-javascript
            // http://stackoverflow.com/questions/1822350/what-is-the-javascript-operator-and-how-do-you-use-it
            var y = (i << 16 | i >>> 16) >>> 0;
            y = ((y & 1431655765) << 1 | (y & 2863311530) >>> 1) >>> 0;
            y = ((y & 858993459) << 2 | (y & 3435973836) >>> 2) >>> 0;
            y = ((y & 252645135) << 4 | (y & 4042322160) >>> 4) >>> 0;
            y = (((y & 16711935) << 8 | (y & 4278255360) >>> 8) >>> 0) / 4294967296;

            // CDF
            var cosTheta = Math.sqrt((1 - y) / (1 + (a * a - 1.0) * y));
            tmp[i] = cosTheta;
        }

        for (var i = 0; i < sampleSize; i++) {
            var offset = (i * roughnessLevels + j) * 4;
            var cosTheta = tmp[i];
            var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta);
            var x = i / sampleSize;
            var phi = 2.0 * Math.PI * x;
            pixels[offset] = sinTheta * Math.cos(phi);
            pixels[offset + 1] = cosTheta;
            pixels[offset + 2] = sinTheta * Math.sin(phi);
            pixels[offset + 3] = 1.0;
        }
    }
    normalDistribution.pixels = pixels;

    return normalDistribution;
};

/* harmony default export */ const util_cubemap = (cubemapUtil);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/AmbientCubemap.js
// https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/AmbientCubemap/



/**
 * Ambient cubemap light provides specular parts of Image Based Lighting.
 * Which is a basic requirement for Physically Based Rendering
 * @constructor clay.light.AmbientCubemap
 * @extends clay.Light
 */
var AmbientCubemapLight = src_Light.extend({

    /**
     * @type {clay.TextureCube}
     * @memberOf clay.light.AmbientCubemap#
     */
    cubemap: null,

    // TODO
    // range: 100,

    castShadow: false,

    _normalDistribution: null,
    _brdfLookup: null

}, /** @lends clay.light.AmbientCubemap# */ {

    type: 'AMBIENT_CUBEMAP_LIGHT',

    /**
     * Do prefitering the cubemap
     * @param {clay.Renderer} renderer
     * @param {number} [size=32]
     */
    prefilter: function (renderer, size) {
        if (!renderer.getGLExtension('EXT_shader_texture_lod')) {
            console.warn('Device not support textureCubeLodEXT');
            return;
        }
        if (!this._brdfLookup) {
            this._normalDistribution = util_cubemap.generateNormalDistribution();
            this._brdfLookup = util_cubemap.integrateBRDF(renderer, this._normalDistribution);
        }
        var cubemap = this.cubemap;
        if (cubemap.__prefiltered) {
            return;
        }

        var result = util_cubemap.prefilterEnvironmentMap(
            renderer, cubemap, {
                encodeRGBM: true,
                width: size,
                height: size
            }, this._normalDistribution, this._brdfLookup
        );
        this.cubemap = result.environmentMap;
        this.cubemap.__prefiltered = true;

        cubemap.dispose(renderer);
    },

    getBRDFLookup: function () {
        return this._brdfLookup;
    },

    uniformTemplates: {
        ambientCubemapLightColor: {
            type: '3f',
            value: function (instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0]*intensity, color[1]*intensity, color[2]*intensity];
            }
        },

        ambientCubemapLightCubemap: {
            type: 't',
            value: function (instance) {
                return instance.cubemap;
            }
        },

        ambientCubemapLightBRDFLookup: {
            type: 't',
            value: function (instance) {
                return instance._brdfLookup;
            }
        }
    }
    /**
     * @function
     * @name clone
     * @return {clay.light.AmbientCubemap}
     * @memberOf clay.light.AmbientCubemap.prototype
     */
});

/* harmony default export */ const AmbientCubemap = (AmbientCubemapLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/AmbientSH.js



/**
 * Spherical Harmonic Ambient Light
 * @constructor clay.light.AmbientSH
 * @extends clay.Light
 */
var AmbientSHLight = src_Light.extend({

    castShadow: false,

    /**
     * Spherical Harmonic Coefficients
     * @type {Array.<number>}
     * @memberOf clay.light.AmbientSH#
     */
    coefficients: [],

}, function () {
    this._coefficientsTmpArr = new core_vendor.Float32Array(9 * 3);
}, {

    type: 'AMBIENT_SH_LIGHT',

    uniformTemplates: {
        ambientSHLightColor: {
            type: '3f',
            value: function (instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0] * intensity, color[1] * intensity, color[2] * intensity];
            }
        },

        ambientSHLightCoefficients: {
            type: '3f',
            value: function (instance) {
                var coefficientsTmpArr = instance._coefficientsTmpArr;
                for (var i = 0; i < instance.coefficients.length; i++) {
                    coefficientsTmpArr[i] = instance.coefficients[i];
                }
                return coefficientsTmpArr;
            }
        }
    }
    /**
     * @function
     * @name clone
     * @return {clay.light.Ambient}
     * @memberOf clay.light.Ambient.prototype
     */
});

/* harmony default export */ const AmbientSH = (AmbientSHLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/shader/projectEnvMap.glsl.js
/* harmony default export */ const projectEnvMap_glsl = ("uniform samplerCube environmentMap;\nvarying vec2 v_Texcoord;\n#define TEXTURE_SIZE 16\nmat3 front = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 1.0, 0.0,\n 0.0, 0.0, 1.0\n);\nmat3 back = mat3(\n -1.0, 0.0, 0.0,\n 0.0, 1.0, 0.0,\n 0.0, 0.0, -1.0\n);\nmat3 left = mat3(\n 0.0, 0.0, -1.0,\n 0.0, 1.0, 0.0,\n 1.0, 0.0, 0.0\n);\nmat3 right = mat3(\n 0.0, 0.0, 1.0,\n 0.0, 1.0, 0.0,\n -1.0, 0.0, 0.0\n);\nmat3 up = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 0.0, 1.0,\n 0.0, -1.0, 0.0\n);\nmat3 down = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 0.0, -1.0,\n 0.0, 1.0, 0.0\n);\nfloat harmonics(vec3 normal){\n int index = int(gl_FragCoord.x);\n float x = normal.x;\n float y = normal.y;\n float z = normal.z;\n if(index==0){\n return 1.0;\n }\n else if(index==1){\n return x;\n }\n else if(index==2){\n return y;\n }\n else if(index==3){\n return z;\n }\n else if(index==4){\n return x*z;\n }\n else if(index==5){\n return y*z;\n }\n else if(index==6){\n return x*y;\n }\n else if(index==7){\n return 3.0*z*z - 1.0;\n }\n else{\n return x*x - y*y;\n }\n}\nvec3 sampleSide(mat3 rot)\n{\n vec3 result = vec3(0.0);\n float divider = 0.0;\n for (int i = 0; i < TEXTURE_SIZE * TEXTURE_SIZE; i++) {\n float x = mod(float(i), float(TEXTURE_SIZE));\n float y = float(i / TEXTURE_SIZE);\n vec2 sidecoord = ((vec2(x, y) + vec2(0.5, 0.5)) / vec2(TEXTURE_SIZE)) * 2.0 - 1.0;\n vec3 normal = normalize(vec3(sidecoord, -1.0));\n vec3 fetchNormal = rot * normal;\n vec3 texel = textureCube(environmentMap, fetchNormal).rgb;\n result += harmonics(fetchNormal) * texel * -normal.z;\n divider += -normal.z;\n }\n return result / divider;\n}\nvoid main()\n{\n vec3 result = (\n sampleSide(front) +\n sampleSide(back) +\n sampleSide(left) +\n sampleSide(right) +\n sampleSide(up) +\n sampleSide(down)\n ) / 6.0;\n gl_FragColor = vec4(result, 1.0);\n}");

;// CONCATENATED MODULE: ./node_modules/claygl/src/util/sh.js
// Spherical Harmonic Helpers










var sh = {};



var sh_targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz'];

// Project on gpu, but needs browser to support readPixels as Float32Array.
function projectEnvironmentMapGPU(renderer, envMap) {
    var shTexture = new src_Texture2D({
        width: 9,
        height: 1,
        type: src_Texture.FLOAT
    });
    var pass = new compositor_Pass({
        fragment: projectEnvMap_glsl
    });
    pass.material.define('fragment', 'TEXTURE_SIZE', envMap.width);
    pass.setUniform('environmentMap', envMap);

    var framebuffer = new src_FrameBuffer();
    framebuffer.attach(shTexture);
    pass.render(renderer, framebuffer);

    framebuffer.bind(renderer);
    // TODO Only chrome and firefox support Float32Array
    var pixels = new core_vendor.Float32Array(9 * 4);
    renderer.gl.readPixels(0, 0, 9, 1, src_Texture.RGBA, src_Texture.FLOAT, pixels);

    var coeff = new core_vendor.Float32Array(9 * 3);
    for (var i = 0; i < 9; i++) {
        coeff[i * 3] = pixels[i * 4];
        coeff[i * 3 + 1] = pixels[i * 4 + 1];
        coeff[i * 3 + 2] = pixels[i * 4 + 2];
    }
    framebuffer.unbind(renderer);

    framebuffer.dispose(renderer);
    pass.dispose(renderer);
    return coeff;
}

function harmonics(normal, index){
    var x = normal[0];
    var y = normal[1];
    var z = normal[2];

    if (index === 0) {
        return 1.0;
    }
    else if (index === 1) {
        return x;
    }
    else if (index === 2) {
        return y;
    }
    else if (index === 3) {
        return z;
    }
    else if (index === 4) {
        return x * z;
    }
    else if (index === 5) {
        return y * z;
    }
    else if (index === 6) {
        return x * y;
    }
    else if (index === 7) {
        return 3.0 * z * z - 1.0;
    }
    else {
        return x * x - y * y;
    }
}

var normalTransform = {
    px: [2, 1, 0, -1, -1, 1],
    nx: [2, 1, 0, 1, -1, -1],
    py: [0, 2, 1, 1, -1, -1],
    ny: [0, 2, 1, 1, 1, 1],
    pz: [0, 1, 2, -1, -1, -1],
    nz: [0, 1, 2, 1, -1, 1]
};

// Project on cpu.
function projectEnvironmentMapCPU(renderer, cubePixels, width, height) {
    var coeff = new core_vendor.Float32Array(9 * 3);
    var normal = glmatrix_vec3.create();
    var texel = glmatrix_vec3.create();
    var fetchNormal = glmatrix_vec3.create();
    for (var m = 0; m < 9; m++) {
        var result = glmatrix_vec3.create();
        for (var k = 0; k < sh_targets.length; k++) {
            var pixels = cubePixels[sh_targets[k]];

            var sideResult = glmatrix_vec3.create();
            var divider = 0;
            var i = 0;
            var transform = normalTransform[sh_targets[k]];
            for (var y = 0; y < height; y++) {
                for (var x = 0; x < width; x++) {

                    normal[0] = x / (width - 1.0) * 2.0 - 1.0;
                    // TODO Flip y?
                    normal[1] = y / (height - 1.0) * 2.0 - 1.0;
                    normal[2] = -1.0;
                    glmatrix_vec3.normalize(normal, normal);

                    fetchNormal[0] = normal[transform[0]] * transform[3];
                    fetchNormal[1] = normal[transform[1]] * transform[4];
                    fetchNormal[2] = normal[transform[2]] * transform[5];

                    texel[0] = pixels[i++] / 255;
                    texel[1] = pixels[i++] / 255;
                    texel[2] = pixels[i++] / 255;
                    // RGBM Decode
                    var scale = pixels[i++] / 255 * 8.12;
                    texel[0] *= scale;
                    texel[1] *= scale;
                    texel[2] *= scale;

                    glmatrix_vec3.scaleAndAdd(sideResult, sideResult, texel, harmonics(fetchNormal, m) * -normal[2]);
                    // -normal.z equals cos(theta) of Lambertian
                    divider += -normal[2];
                }
            }
            glmatrix_vec3.scaleAndAdd(result, result, sideResult, 1 / divider);
        }

        coeff[m * 3] = result[0] / 6.0;
        coeff[m * 3 + 1] = result[1] / 6.0;
        coeff[m * 3 + 2] = result[2] / 6.0;
    }
    return coeff;
}

/**
 * @param  {clay.Renderer} renderer
 * @param  {clay.Texture} envMap
 * @param  {Object} [textureOpts]
 * @param  {Object} [textureOpts.lod]
 * @param  {boolean} [textureOpts.decodeRGBM]
 */
sh.projectEnvironmentMap = function (renderer, envMap, opts) {

    // TODO sRGB

    opts = opts || {};
    opts.lod = opts.lod || 0;

    var skybox;
    var dummyScene = new src_Scene();
    var size = 64;
    if (envMap.textureType === 'texture2D') {
        skybox = new Skydome({
            scene: dummyScene,
            environmentMap: envMap
        });
    }
    else {
        size = (envMap.image && envMap.image.px) ? envMap.image.px.width : envMap.width;
        skybox = new plugin_Skybox({
            scene: dummyScene,
            environmentMap: envMap
        });
    }
    // Convert to rgbm
    var width = Math.ceil(size / Math.pow(2, opts.lod));
    var height = Math.ceil(size / Math.pow(2, opts.lod));
    var rgbmTexture = new src_Texture2D({
        width: width,
        height: height
    });
    var framebuffer = new src_FrameBuffer();
    skybox.material.define('fragment', 'RGBM_ENCODE');
    if (opts.decodeRGBM) {
        skybox.material.define('fragment', 'RGBM_DECODE');
    }
    skybox.material.set('lod', opts.lod);
    var envMapPass = new EnvironmentMap({
        texture: rgbmTexture
    });
    var cubePixels = {};
    for (var i = 0; i < sh_targets.length; i++) {
        cubePixels[sh_targets[i]] = new Uint8Array(width * height * 4);
        var camera = envMapPass.getCamera(sh_targets[i]);
        camera.fov = 90;
        framebuffer.attach(rgbmTexture);
        framebuffer.bind(renderer);
        renderer.render(dummyScene, camera);
        renderer.gl.readPixels(
            0, 0, width, height,
            src_Texture.RGBA, src_Texture.UNSIGNED_BYTE, cubePixels[sh_targets[i]]
        );
        framebuffer.unbind(renderer);
    }

    skybox.dispose(renderer);
    framebuffer.dispose(renderer);
    rgbmTexture.dispose(renderer);

    return projectEnvironmentMapCPU(renderer, cubePixels, width, height);
};

/* harmony default export */ const util_sh = (sh);

;// CONCATENATED MODULE: ./src/util/retrieve.js


var retrieve = {

    firstNotNull: function () {
        for (var i = 0, len = arguments.length; i < len; i++) {
            if (arguments[i] != null) {
                return arguments[i];
            }
        }
    },

    /**
     * @param {module:echarts/data/List} data
     * @param {Object} payload Contains dataIndex (means rawIndex) / dataIndexInside / name
     *                         each of which can be Array or primary type.
     * @return {number|Array.<number>} dataIndex If not found, return undefined/null.
     */
    queryDataIndex: function (data, payload) {
        if (payload.dataIndexInside != null) {
            return payload.dataIndexInside;
        }
        else if (payload.dataIndex != null) {
            return external_echarts_.util.isArray(payload.dataIndex)
                ? external_echarts_.util.map(payload.dataIndex, function (value) {
                    return data.indexOfRawIndex(value);
                })
                : data.indexOfRawIndex(payload.dataIndex);
        }
        else if (payload.name != null) {
            return external_echarts_.util.isArray(payload.name)
                ? external_echarts_.util.map(payload.name, function (value) {
                    return data.indexOfName(value);
                })
                : data.indexOfName(payload.name);
        }
    }
};

/* harmony default export */ const util_retrieve = (retrieve);
;// CONCATENATED MODULE: ./node_modules/claygl/src/geometry/Sphere.js



/**
 * @constructor clay.geometry.Sphere
 * @extends clay.Geometry
 * @param {Object} [opt]
 * @param {number} [widthSegments]
 * @param {number} [heightSegments]
 * @param {number} [phiStart]
 * @param {number} [phiLength]
 * @param {number} [thetaStart]
 * @param {number} [thetaLength]
 * @param {number} [radius]
 */
var Sphere = src_Geometry.extend(/** @lends clay.geometry.Sphere# */ {
    dynamic: false,
    /**
     * @type {number}
     */
    widthSegments: 40,
    /**
     * @type {number}
     */
    heightSegments: 20,

    /**
     * @type {number}
     */
    phiStart: 0,
    /**
     * @type {number}
     */
    phiLength: Math.PI * 2,

    /**
     * @type {number}
     */
    thetaStart: 0,
    /**
     * @type {number}
     */
    thetaLength: Math.PI,

    /**
     * @type {number}
     */
    radius: 1

}, function() {
    this.build();
},
/** @lends clay.geometry.Sphere.prototype */
{
    /**
     * Build sphere geometry
     */
    build: function() {
        var heightSegments = this.heightSegments;
        var widthSegments = this.widthSegments;

        var positionAttr = this.attributes.position;
        var texcoordAttr = this.attributes.texcoord0;
        var normalAttr = this.attributes.normal;

        var vertexCount = (widthSegments + 1) * (heightSegments + 1);
        positionAttr.init(vertexCount);
        texcoordAttr.init(vertexCount);
        normalAttr.init(vertexCount);

        var IndicesCtor = vertexCount > 0xffff ? Uint32Array : Uint16Array;
        var indices = this.indices = new IndicesCtor(widthSegments * heightSegments * 6);

        var x, y, z,
            u, v,
            i, j;

        var radius = this.radius;
        var phiStart = this.phiStart;
        var phiLength = this.phiLength;
        var thetaStart = this.thetaStart;
        var thetaLength = this.thetaLength;
        var radius = this.radius;

        var pos = [];
        var uv = [];
        var offset = 0;
        var divider = 1 / radius;
        for (j = 0; j <= heightSegments; j ++) {
            for (i = 0; i <= widthSegments; i ++) {
                u = i / widthSegments;
                v = j / heightSegments;

                // X axis is inverted so texture can be mapped from left to right
                x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
                y = radius * Math.cos(thetaStart + v * thetaLength);
                z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);

                pos[0] = x; pos[1] = y; pos[2] = z;
                uv[0] = u; uv[1] = v;
                positionAttr.set(offset, pos);
                texcoordAttr.set(offset, uv);
                pos[0] *= divider;
                pos[1] *= divider;
                pos[2] *= divider;
                normalAttr.set(offset, pos);
                offset++;
            }
        }

        var i1, i2, i3, i4;

        var len = widthSegments + 1;

        var n = 0;
        for (j = 0; j < heightSegments; j ++) {
            for (i = 0; i < widthSegments; i ++) {
                i2 = j * len + i;
                i1 = (j * len + i + 1);
                i4 = (j + 1) * len + i + 1;
                i3 = (j + 1) * len + i;

                indices[n++] = i1;
                indices[n++] = i2;
                indices[n++] = i4;

                indices[n++] = i2;
                indices[n++] = i3;
                indices[n++] = i4;
            }
        }

        this.boundingBox = new math_BoundingBox();
        this.boundingBox.max.set(radius, radius, radius);
        this.boundingBox.min.set(-radius, -radius, -radius);
    }
});

/* harmony default export */ const geometry_Sphere = (Sphere);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/Ambient.js


/**
 * @constructor clay.light.Ambient
 * @extends clay.Light
 */
var AmbientLight = src_Light.extend({

    castShadow: false

}, {

    type: 'AMBIENT_LIGHT',

    uniformTemplates: {
        ambientLightColor: {
            type: '3f',
            value: function(instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0]*intensity, color[1]*intensity, color[2]*intensity];
            }
        }
    }
    /**
     * @function
     * @name clone
     * @return {clay.light.Ambient}
     * @memberOf clay.light.Ambient.prototype
     */
});

/* harmony default export */ const Ambient = (AmbientLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/Directional.js



/**
 * @constructor clay.light.Directional
 * @extends clay.Light
 *
 * @example
 *     var light = new clay.light.Directional({
 *         intensity: 0.5,
 *         color: [1.0, 0.0, 0.0]
 *     });
 *     light.position.set(10, 10, 10);
 *     light.lookAt(clay.Vector3.ZERO);
 *     scene.add(light);
 */
var DirectionalLight = src_Light.extend(/** @lends clay.light.Directional# */ {
    /**
     * @type {number}
     */
    shadowBias: 0.001,
    /**
     * @type {number}
     */
    shadowSlopeScale: 2.0,
    /**
     * Shadow cascade.
     * Use PSSM technique when it is larger than 1 and have a unique directional light in scene.
     * @type {number}
     */
    shadowCascade: 1,

    /**
     * Available when shadowCascade is larger than 1 and have a unique directional light in scene.
     * @type {number}
     */
    cascadeSplitLogFactor: 0.2
}, {

    type: 'DIRECTIONAL_LIGHT',

    uniformTemplates: {
        directionalLightDirection: {
            type: '3f',
            value: function (instance) {
                instance.__dir = instance.__dir || new math_Vector3();
                // Direction is target to eye
                return instance.__dir.copy(instance.worldTransform.z).normalize().negate().array;
            }
        },
        directionalLightColor: {
            type: '3f',
            value: function (instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0] * intensity, color[1] * intensity, color[2] * intensity];
            }
        }
    },
    /**
     * @return {clay.light.Directional}
     * @memberOf clay.light.Directional.prototype
     */
    clone: function () {
        var light = src_Light.prototype.clone.call(this);
        light.shadowBias = this.shadowBias;
        light.shadowSlopeScale = this.shadowSlopeScale;
        return light;
    }
});

/* harmony default export */ const Directional = (DirectionalLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/Point.js


/**
 * @constructor clay.light.Point
 * @extends clay.Light
 */
var PointLight = src_Light.extend(/** @lends clay.light.Point# */ {
    /**
     * @type {number}
     */
    range: 100,

    /**
     * @type {number}
     */
    castShadow: false
}, {

    type: 'POINT_LIGHT',

    uniformTemplates: {
        pointLightPosition: {
            type: '3f',
            value: function(instance) {
                return instance.getWorldPosition().array;
            }
        },
        pointLightRange: {
            type: '1f',
            value: function(instance) {
                return instance.range;
            }
        },
        pointLightColor: {
            type: '3f',
            value: function(instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0] * intensity, color[1] * intensity, color[2] * intensity];
            }
        }
    },
    /**
     * @return {clay.light.Point}
     * @memberOf clay.light.Point.prototype
     */
    clone: function() {
        var light = src_Light.prototype.clone.call(this);
        light.range = this.range;
        return light;
    }
});

/* harmony default export */ const Point = (PointLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/light/Spot.js



/**
 * @constructor clay.light.Spot
 * @extends clay.Light
 */
var SpotLight = src_Light.extend(/**@lends clay.light.Spot */ {
    /**
     * @type {number}
     */
    range: 20,
    /**
     * @type {number}
     */
    umbraAngle: 30,
    /**
     * @type {number}
     */
    penumbraAngle: 45,
    /**
     * @type {number}
     */
    falloffFactor: 2.0,
    /**
     * @type {number}
     */
    shadowBias: 0.001,
    /**
     * @type {number}
     */
    shadowSlopeScale: 2.0
}, {

    type: 'SPOT_LIGHT',

    uniformTemplates: {
        spotLightPosition: {
            type: '3f',
            value: function (instance) {
                return instance.getWorldPosition().array;
            }
        },
        spotLightRange: {
            type: '1f',
            value: function (instance) {
                return instance.range;
            }
        },
        spotLightUmbraAngleCosine: {
            type: '1f',
            value: function (instance) {
                return Math.cos(instance.umbraAngle * Math.PI / 180);
            }
        },
        spotLightPenumbraAngleCosine: {
            type: '1f',
            value: function (instance) {
                return Math.cos(instance.penumbraAngle * Math.PI / 180);
            }
        },
        spotLightFalloffFactor: {
            type: '1f',
            value: function (instance) {
                return instance.falloffFactor;
            }
        },
        spotLightDirection: {
            type: '3f',
            value: function (instance) {
                instance.__dir = instance.__dir || new math_Vector3();
                // Direction is target to eye
                return instance.__dir.copy(instance.worldTransform.z).negate().array;
            }
        },
        spotLightColor: {
            type: '3f',
            value: function (instance) {
                var color = instance.color;
                var intensity = instance.intensity;
                return [color[0] * intensity, color[1] * intensity, color[2] * intensity];
            }
        }
    },
    /**
     * @return {clay.light.Spot}
     * @memberOf clay.light.Spot.prototype
     */
    clone: function () {
        var light = src_Light.prototype.clone.call(this);
        light.range = this.range;
        light.umbraAngle = this.umbraAngle;
        light.penumbraAngle = this.penumbraAngle;
        light.falloffFactor = this.falloffFactor;
        light.shadowBias = this.shadowBias;
        light.shadowSlopeScale = this.shadowSlopeScale;
        return light;
    }
});

/* harmony default export */ const Spot = (SpotLight);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Vector4.js


/**
 * @constructor
 * @alias clay.Vector4
 * @param {number} x
 * @param {number} y
 * @param {number} z
 * @param {number} w
 */
var Vector4 = function(x, y, z, w) {

    x = x || 0;
    y = y || 0;
    z = z || 0;
    w = w || 0;

    /**
     * Storage of Vector4, read and write of x, y, z, w will change the values in array
     * All methods also operate on the array instead of x, y, z, w components
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Vector4#
     */
    this.array = glmatrix_vec4.fromValues(x, y, z, w);

    /**
     * Dirty flag is used by the Node to determine
     * if the matrix is updated to latest
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Vector4#
     */
    this._dirty = true;
};

Vector4.prototype = {

    constructor: Vector4,

    /**
     * Add b to self
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    add: function(b) {
        glmatrix_vec4.add(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y and z components
     * @param  {number}  x
     * @param  {number}  y
     * @param  {number}  z
     * @param  {number}  w
     * @return {clay.Vector4}
     */
    set: function(x, y, z, w) {
        this.array[0] = x;
        this.array[1] = y;
        this.array[2] = z;
        this.array[3] = w;
        this._dirty = true;
        return this;
    },

    /**
     * Set x, y, z and w components from array
     * @param  {Float32Array|number[]} arr
     * @return {clay.Vector4}
     */
    setArray: function(arr) {
        this.array[0] = arr[0];
        this.array[1] = arr[1];
        this.array[2] = arr[2];
        this.array[3] = arr[3];

        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Vector4
     * @return {clay.Vector4}
     */
    clone: function() {
        return new Vector4(this.x, this.y, this.z, this.w);
    },

    /**
     * Copy from b
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    copy: function(b) {
        glmatrix_vec4.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for distance
     * @param  {clay.Vector4} b
     * @return {number}
     */
    dist: function(b) {
        return glmatrix_vec4.dist(this.array, b.array);
    },

    /**
     * Distance between self and b
     * @param  {clay.Vector4} b
     * @return {number}
     */
    distance: function(b) {
        return glmatrix_vec4.distance(this.array, b.array);
    },

    /**
     * Alias for divide
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    div: function(b) {
        glmatrix_vec4.div(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Divide self by b
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    divide: function(b) {
        glmatrix_vec4.divide(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Dot product of self and b
     * @param  {clay.Vector4} b
     * @return {number}
     */
    dot: function(b) {
        return glmatrix_vec4.dot(this.array, b.array);
    },

    /**
     * Alias of length
     * @return {number}
     */
    len: function() {
        return glmatrix_vec4.len(this.array);
    },

    /**
     * Calculate the length
     * @return {number}
     */
    length: function() {
        return glmatrix_vec4.length(this.array);
    },
    /**
     * Linear interpolation between a and b
     * @param  {clay.Vector4} a
     * @param  {clay.Vector4} b
     * @param  {number}  t
     * @return {clay.Vector4}
     */
    lerp: function(a, b, t) {
        glmatrix_vec4.lerp(this.array, a.array, b.array, t);
        this._dirty = true;
        return this;
    },

    /**
     * Minimum of self and b
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    min: function(b) {
        glmatrix_vec4.min(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Maximum of self and b
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    max: function(b) {
        glmatrix_vec4.max(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiply
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    mul: function(b) {
        glmatrix_vec4.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Mutiply self and b
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    multiply: function(b) {
        glmatrix_vec4.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Negate self
     * @return {clay.Vector4}
     */
    negate: function() {
        glmatrix_vec4.negate(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Normalize self
     * @return {clay.Vector4}
     */
    normalize: function() {
        glmatrix_vec4.normalize(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Generate random x, y, z, w components with a given scale
     * @param  {number} scale
     * @return {clay.Vector4}
     */
    random: function(scale) {
        glmatrix_vec4.random(this.array, scale);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self
     * @param  {number}  scale
     * @return {clay.Vector4}
     */
    scale: function(s) {
        glmatrix_vec4.scale(this.array, this.array, s);
        this._dirty = true;
        return this;
    },
    /**
     * Scale b and add to self
     * @param  {clay.Vector4} b
     * @param  {number}  scale
     * @return {clay.Vector4}
     */
    scaleAndAdd: function(b, s) {
        glmatrix_vec4.scaleAndAdd(this.array, this.array, b.array, s);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for squaredDistance
     * @param  {clay.Vector4} b
     * @return {number}
     */
    sqrDist: function(b) {
        return glmatrix_vec4.sqrDist(this.array, b.array);
    },

    /**
     * Squared distance between self and b
     * @param  {clay.Vector4} b
     * @return {number}
     */
    squaredDistance: function(b) {
        return glmatrix_vec4.squaredDistance(this.array, b.array);
    },

    /**
     * Alias for squaredLength
     * @return {number}
     */
    sqrLen: function() {
        return glmatrix_vec4.sqrLen(this.array);
    },

    /**
     * Squared length of self
     * @return {number}
     */
    squaredLength: function() {
        return glmatrix_vec4.squaredLength(this.array);
    },

    /**
     * Alias for subtract
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    sub: function(b) {
        glmatrix_vec4.sub(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Subtract b from self
     * @param  {clay.Vector4} b
     * @return {clay.Vector4}
     */
    subtract: function(b) {
        glmatrix_vec4.subtract(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Matrix4 m
     * @param  {clay.Matrix4} m
     * @return {clay.Vector4}
     */
    transformMat4: function(m) {
        glmatrix_vec4.transformMat4(this.array, this.array, m.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transform self with a Quaternion q
     * @param  {clay.Quaternion} q
     * @return {clay.Vector4}
     */
    transformQuat: function(q) {
        glmatrix_vec4.transformQuat(this.array, this.array, q.array);
        this._dirty = true;
        return this;
    },

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

var Vector4_defineProperty = Object.defineProperty;
// Getter and Setter
if (Vector4_defineProperty) {

    var Vector4_proto = Vector4.prototype;
    /**
     * @name x
     * @type {number}
     * @memberOf clay.Vector4
     * @instance
     */
    Vector4_defineProperty(Vector4_proto, 'x', {
        get: function () {
            return this.array[0];
        },
        set: function (value) {
            this.array[0] = value;
            this._dirty = true;
        }
    });

    /**
     * @name y
     * @type {number}
     * @memberOf clay.Vector4
     * @instance
     */
    Vector4_defineProperty(Vector4_proto, 'y', {
        get: function () {
            return this.array[1];
        },
        set: function (value) {
            this.array[1] = value;
            this._dirty = true;
        }
    });

    /**
     * @name z
     * @type {number}
     * @memberOf clay.Vector4
     * @instance
     */
    Vector4_defineProperty(Vector4_proto, 'z', {
        get: function () {
            return this.array[2];
        },
        set: function (value) {
            this.array[2] = value;
            this._dirty = true;
        }
    });

    /**
     * @name w
     * @type {number}
     * @memberOf clay.Vector4
     * @instance
     */
    Vector4_defineProperty(Vector4_proto, 'w', {
        get: function () {
            return this.array[3];
        },
        set: function (value) {
            this.array[3] = value;
            this._dirty = true;
        }
    });
}

// Supply methods that are not in place

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.add = function(out, a, b) {
    glmatrix_vec4.add(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {number}  x
 * @param  {number}  y
 * @param  {number}  z
 * @return {clay.Vector4}
 */
Vector4.set = function(out, x, y, z, w) {
    glmatrix_vec4.set(out.array, x, y, z, w);
    out._dirty = true;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.copy = function(out, b) {
    glmatrix_vec4.copy(out.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {number}
 */
Vector4.dist = function(a, b) {
    return glmatrix_vec4.distance(a.array, b.array);
};

/**
 * @function
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {number}
 */
Vector4.distance = Vector4.dist;

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.div = function(out, a, b) {
    glmatrix_vec4.divide(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.divide = Vector4.div;

/**
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {number}
 */
Vector4.dot = function(a, b) {
    return glmatrix_vec4.dot(a.array, b.array);
};

/**
 * @param  {clay.Vector4} a
 * @return {number}
 */
Vector4.len = function(b) {
    return glmatrix_vec4.length(b.array);
};

// Vector4.length = Vector4.len;

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @param  {number}  t
 * @return {clay.Vector4}
 */
Vector4.lerp = function(out, a, b, t) {
    glmatrix_vec4.lerp(out.array, a.array, b.array, t);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.min = function(out, a, b) {
    glmatrix_vec4.min(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.max = function(out, a, b) {
    glmatrix_vec4.max(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.mul = function(out, a, b) {
    glmatrix_vec4.multiply(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.multiply = Vector4.mul;

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @return {clay.Vector4}
 */
Vector4.negate = function(out, a) {
    glmatrix_vec4.negate(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @return {clay.Vector4}
 */
Vector4.normalize = function(out, a) {
    glmatrix_vec4.normalize(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {number}  scale
 * @return {clay.Vector4}
 */
Vector4.random = function(out, scale) {
    glmatrix_vec4.random(out.array, scale);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {number}  scale
 * @return {clay.Vector4}
 */
Vector4.scale = function(out, a, scale) {
    glmatrix_vec4.scale(out.array, a.array, scale);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @param  {number}  scale
 * @return {clay.Vector4}
 */
Vector4.scaleAndAdd = function(out, a, b, scale) {
    glmatrix_vec4.scaleAndAdd(out.array, a.array, b.array, scale);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {number}
 */
Vector4.sqrDist = function(a, b) {
    return glmatrix_vec4.sqrDist(a.array, b.array);
};

/**
 * @function
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {number}
 */
Vector4.squaredDistance = Vector4.sqrDist;

/**
 * @param  {clay.Vector4} a
 * @return {number}
 */
Vector4.sqrLen = function(a) {
    return glmatrix_vec4.sqrLen(a.array);
};
/**
 * @function
 * @param  {clay.Vector4} a
 * @return {number}
 */
Vector4.squaredLength = Vector4.sqrLen;

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.sub = function(out, a, b) {
    glmatrix_vec4.subtract(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};
/**
 * @function
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Vector4} b
 * @return {clay.Vector4}
 */
Vector4.subtract = Vector4.sub;

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Matrix4} m
 * @return {clay.Vector4}
 */
Vector4.transformMat4 = function(out, a, m) {
    glmatrix_vec4.transformMat4(out.array, a.array, m.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Vector4} out
 * @param  {clay.Vector4} a
 * @param  {clay.Quaternion} q
 * @return {clay.Vector4}
 */
Vector4.transformQuat = function(out, a, q) {
    glmatrix_vec4.transformQuat(out.array, a.array, q.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Vector4 = (Vector4);

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat2.js


/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 2x2 Matrix
 * @name mat2
 */

var mat2 = {};

/**
 * Creates a new identity mat2
 *
 * @returns {mat2} a new 2x2 matrix
 */
mat2.create = function() {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Creates a new mat2 initialized with values from an existing matrix
 *
 * @param {mat2} a matrix to clone
 * @returns {mat2} a new 2x2 matrix
 */
mat2.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(4);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Copy the values from one mat2 to another
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.copy = function(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
};

/**
 * Set a mat2 to the identity matrix
 *
 * @param {mat2} out the receiving matrix
 * @returns {mat2} out
 */
mat2.identity = function(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    return out;
};

/**
 * Transpose the values of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.transpose = function(out, a) {
    // If we are transposing ourselves we can skip a few steps but have to cache some values
    if (out === a) {
        var a1 = a[1];
        out[1] = a[2];
        out[2] = a1;
    } else {
        out[0] = a[0];
        out[1] = a[2];
        out[2] = a[1];
        out[3] = a[3];
    }

    return out;
};

/**
 * Inverts a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.invert = function(out, a) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],

        // Calculate the determinant
        det = a0 * a3 - a2 * a1;

    if (!det) {
        return null;
    }
    det = 1.0 / det;

    out[0] =  a3 * det;
    out[1] = -a1 * det;
    out[2] = -a2 * det;
    out[3] =  a0 * det;

    return out;
};

/**
 * Calculates the adjugate of a mat2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the source matrix
 * @returns {mat2} out
 */
mat2.adjoint = function(out, a) {
    // Caching this value is nessecary if out == a
    var a0 = a[0];
    out[0] =  a[3];
    out[1] = -a[1];
    out[2] = -a[2];
    out[3] =  a0;

    return out;
};

/**
 * Calculates the determinant of a mat2
 *
 * @param {mat2} a the source matrix
 * @returns {Number} determinant of a
 */
mat2.determinant = function (a) {
    return a[0] * a[3] - a[2] * a[1];
};

/**
 * Multiplies two mat2's
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the first operand
 * @param {mat2} b the second operand
 * @returns {mat2} out
 */
mat2.multiply = function (out, a, b) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
    out[0] = a0 * b0 + a2 * b1;
    out[1] = a1 * b0 + a3 * b1;
    out[2] = a0 * b2 + a2 * b3;
    out[3] = a1 * b2 + a3 * b3;
    return out;
};

/**
 * Alias for {@link mat2.multiply}
 * @function
 */
mat2.mul = mat2.multiply;

/**
 * Rotates a mat2 by the given angle
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2} out
 */
mat2.rotate = function (out, a, rad) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = a0 *  c + a2 * s;
    out[1] = a1 *  c + a3 * s;
    out[2] = a0 * -s + a2 * c;
    out[3] = a1 * -s + a3 * c;
    return out;
};

/**
 * Scales the mat2 by the dimensions in the given vec2
 *
 * @param {mat2} out the receiving matrix
 * @param {mat2} a the matrix to rotate
 * @param {vec2} v the vec2 to scale the matrix by
 * @returns {mat2} out
 **/
mat2.scale = function(out, a, v) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
        v0 = v[0], v1 = v[1];
    out[0] = a0 * v0;
    out[1] = a1 * v0;
    out[2] = a2 * v1;
    out[3] = a3 * v1;
    return out;
};

/**
 * Returns Frobenius norm of a mat2
 *
 * @param {mat2} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat2.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)))
};

/**
 * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix
 * @param {mat2} L the lower triangular matrix
 * @param {mat2} D the diagonal matrix
 * @param {mat2} U the upper triangular matrix
 * @param {mat2} a the input matrix to factorize
 */

mat2.LDU = function (L, D, U, a) {
    L[2] = a[2]/a[0];
    U[0] = a[0];
    U[1] = a[1];
    U[3] = a[3] - L[2] * U[1];
    return [L, D, U];
};


/* harmony default export */ const glmatrix_mat2 = (mat2);
;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Matrix2.js


/**
 * @constructor
 * @alias clay.Matrix2
 */
var Matrix2 = function() {

    /**
     * Storage of Matrix2
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Matrix2#
     */
    this.array = glmatrix_mat2.create();

    /**
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Matrix2#
     */
    this._dirty = true;
};

Matrix2.prototype = {

    constructor: Matrix2,

    /**
     * Set components from array
     * @param  {Float32Array|number[]} arr
     */
    setArray: function (arr) {
        for (var i = 0; i < this.array.length; i++) {
            this.array[i] = arr[i];
        }
        this._dirty = true;
        return this;
    },
    /**
     * Clone a new Matrix2
     * @return {clay.Matrix2}
     */
    clone: function() {
        return (new Matrix2()).copy(this);
    },

    /**
     * Copy from b
     * @param  {clay.Matrix2} b
     * @return {clay.Matrix2}
     */
    copy: function(b) {
        glmatrix_mat2.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate the adjugate of self, in-place
     * @return {clay.Matrix2}
     */
    adjoint: function() {
        glmatrix_mat2.adjoint(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate matrix determinant
     * @return {number}
     */
    determinant: function() {
        return glmatrix_mat2.determinant(this.array);
    },

    /**
     * Set to a identity matrix
     * @return {clay.Matrix2}
     */
    identity: function() {
        glmatrix_mat2.identity(this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Invert self
     * @return {clay.Matrix2}
     */
    invert: function() {
        glmatrix_mat2.invert(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for mutiply
     * @param  {clay.Matrix2} b
     * @return {clay.Matrix2}
     */
    mul: function(b) {
        glmatrix_mat2.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiplyLeft
     * @param  {clay.Matrix2} a
     * @return {clay.Matrix2}
     */
    mulLeft: function(a) {
        glmatrix_mat2.mul(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply self and b
     * @param  {clay.Matrix2} b
     * @return {clay.Matrix2}
     */
    multiply: function(b) {
        glmatrix_mat2.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply a and self, a is on the left
     * @param  {clay.Matrix2} a
     * @return {clay.Matrix2}
     */
    multiplyLeft: function(a) {
        glmatrix_mat2.multiply(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian
     * @param  {number}   rad
     * @return {clay.Matrix2}
     */
    rotate: function(rad) {
        glmatrix_mat2.rotate(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self by s
     * @param  {clay.Vector2}  s
     * @return {clay.Matrix2}
     */
    scale: function(v) {
        glmatrix_mat2.scale(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },
    /**
     * Transpose self, in-place.
     * @return {clay.Matrix2}
     */
    transpose: function() {
        glmatrix_mat2.transpose(this.array, this.array);
        this._dirty = true;
        return this;
    },

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

/**
 * @param  {Matrix2} out
 * @param  {Matrix2} a
 * @return {Matrix2}
 */
Matrix2.adjoint = function(out, a) {
    glmatrix_mat2.adjoint(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @return {clay.Matrix2}
 */
Matrix2.copy = function(out, a) {
    glmatrix_mat2.copy(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2} a
 * @return {number}
 */
Matrix2.determinant = function(a) {
    return glmatrix_mat2.determinant(a.array);
};

/**
 * @param  {clay.Matrix2} out
 * @return {clay.Matrix2}
 */
Matrix2.identity = function(out) {
    glmatrix_mat2.identity(out.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @return {clay.Matrix2}
 */
Matrix2.invert = function(out, a) {
    glmatrix_mat2.invert(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @param  {clay.Matrix2} b
 * @return {clay.Matrix2}
 */
Matrix2.mul = function(out, a, b) {
    glmatrix_mat2.mul(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @param  {clay.Matrix2} b
 * @return {clay.Matrix2}
 */
Matrix2.multiply = Matrix2.mul;

/**
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @param  {number}   rad
 * @return {clay.Matrix2}
 */
Matrix2.rotate = function(out, a, rad) {
    glmatrix_mat2.rotate(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2} out
 * @param  {clay.Matrix2} a
 * @param  {clay.Vector2}  v
 * @return {clay.Matrix2}
 */
Matrix2.scale = function(out, a, v) {
    glmatrix_mat2.scale(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};
/**
 * @param  {Matrix2} out
 * @param  {Matrix2} a
 * @return {Matrix2}
 */
Matrix2.transpose = function(out, a) {
    glmatrix_mat2.transpose(out.array, a.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Matrix2 = (Matrix2);

;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/mat2d.js

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */



/**
 * @class 2x3 Matrix
 * @name mat2d
 *
 * @description
 * A mat2d contains six elements defined as:
 * <pre>
 * [a, c, tx,
 *  b, d, ty]
 * </pre>
 * This is a short form for the 3x3 matrix:
 * <pre>
 * [a, c, tx,
 *  b, d, ty,
 *  0, 0, 1]
 * </pre>
 * The last row is ignored so the array is shorter and operations are faster.
 */

var mat2d = {};

/**
 * Creates a new identity mat2d
 *
 * @returns {mat2d} a new 2x3 matrix
 */
mat2d.create = function() {
    var out = new GLMAT_ARRAY_TYPE(6);
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    out[4] = 0;
    out[5] = 0;
    return out;
};

/**
 * Creates a new mat2d initialized with values from an existing matrix
 *
 * @param {mat2d} a matrix to clone
 * @returns {mat2d} a new 2x3 matrix
 */
mat2d.clone = function(a) {
    var out = new GLMAT_ARRAY_TYPE(6);
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[4] = a[4];
    out[5] = a[5];
    return out;
};

/**
 * Copy the values from one mat2d to another
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the source matrix
 * @returns {mat2d} out
 */
mat2d.copy = function(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];
    return out;
};

/**
 * Set a mat2d to the identity matrix
 *
 * @param {mat2d} out the receiving matrix
 * @returns {mat2d} out
 */
mat2d.identity = function(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    out[4] = 0;
    out[5] = 0;
    return out;
};

/**
 * Inverts a mat2d
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the source matrix
 * @returns {mat2d} out
 */
mat2d.invert = function(out, a) {
    var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
        atx = a[4], aty = a[5];

    var det = aa * ad - ab * ac;
    if(!det){
        return null;
    }
    det = 1.0 / det;

    out[0] = ad * det;
    out[1] = -ab * det;
    out[2] = -ac * det;
    out[3] = aa * det;
    out[4] = (ac * aty - ad * atx) * det;
    out[5] = (ab * atx - aa * aty) * det;
    return out;
};

/**
 * Calculates the determinant of a mat2d
 *
 * @param {mat2d} a the source matrix
 * @returns {Number} determinant of a
 */
mat2d.determinant = function (a) {
    return a[0] * a[3] - a[1] * a[2];
};

/**
 * Multiplies two mat2d's
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the first operand
 * @param {mat2d} b the second operand
 * @returns {mat2d} out
 */
mat2d.multiply = function (out, a, b) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
        b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
    out[0] = a0 * b0 + a2 * b1;
    out[1] = a1 * b0 + a3 * b1;
    out[2] = a0 * b2 + a2 * b3;
    out[3] = a1 * b2 + a3 * b3;
    out[4] = a0 * b4 + a2 * b5 + a4;
    out[5] = a1 * b4 + a3 * b5 + a5;
    return out;
};

/**
 * Alias for {@link mat2d.multiply}
 * @function
 */
mat2d.mul = mat2d.multiply;


/**
 * Rotates a mat2d by the given angle
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the matrix to rotate
 * @param {Number} rad the angle to rotate the matrix by
 * @returns {mat2d} out
 */
mat2d.rotate = function (out, a, rad) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
        s = Math.sin(rad),
        c = Math.cos(rad);
    out[0] = a0 *  c + a2 * s;
    out[1] = a1 *  c + a3 * s;
    out[2] = a0 * -s + a2 * c;
    out[3] = a1 * -s + a3 * c;
    out[4] = a4;
    out[5] = a5;
    return out;
};

/**
 * Scales the mat2d by the dimensions in the given vec2
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the matrix to translate
 * @param {vec2} v the vec2 to scale the matrix by
 * @returns {mat2d} out
 **/
mat2d.scale = function(out, a, v) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
        v0 = v[0], v1 = v[1];
    out[0] = a0 * v0;
    out[1] = a1 * v0;
    out[2] = a2 * v1;
    out[3] = a3 * v1;
    out[4] = a4;
    out[5] = a5;
    return out;
};

/**
 * Translates the mat2d by the dimensions in the given vec2
 *
 * @param {mat2d} out the receiving matrix
 * @param {mat2d} a the matrix to translate
 * @param {vec2} v the vec2 to translate the matrix by
 * @returns {mat2d} out
 **/
mat2d.translate = function(out, a, v) {
    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
        v0 = v[0], v1 = v[1];
    out[0] = a0;
    out[1] = a1;
    out[2] = a2;
    out[3] = a3;
    out[4] = a0 * v0 + a2 * v1 + a4;
    out[5] = a1 * v0 + a3 * v1 + a5;
    return out;
};

/**
 * Returns Frobenius norm of a mat2d
 *
 * @param {mat2d} a the matrix to calculate Frobenius norm of
 * @returns {Number} Frobenius norm
 */
mat2d.frob = function (a) {
    return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1))
};


/* harmony default export */ const glmatrix_mat2d = (mat2d);
;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Matrix2d.js


/**
 * @constructor
 * @alias clay.Matrix2d
 */
var Matrix2d = function() {
    /**
     * Storage of Matrix2d
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Matrix2d#
     */
    this.array = glmatrix_mat2d.create();

    /**
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Matrix2d#
     */
    this._dirty = true;
};

Matrix2d.prototype = {

    constructor: Matrix2d,

    /**
     * Set components from array
     * @param  {Float32Array|number[]} arr
     */
    setArray: function (arr) {
        for (var i = 0; i < this.array.length; i++) {
            this.array[i] = arr[i];
        }
        this._dirty = true;
        return this;
    },
    /**
     * Clone a new Matrix2d
     * @return {clay.Matrix2d}
     */
    clone: function() {
        return (new Matrix2d()).copy(this);
    },

    /**
     * Copy from b
     * @param  {clay.Matrix2d} b
     * @return {clay.Matrix2d}
     */
    copy: function(b) {
        glmatrix_mat2d.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate matrix determinant
     * @return {number}
     */
    determinant: function() {
        return glmatrix_mat2d.determinant(this.array);
    },

    /**
     * Set to a identity matrix
     * @return {clay.Matrix2d}
     */
    identity: function() {
        glmatrix_mat2d.identity(this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Invert self
     * @return {clay.Matrix2d}
     */
    invert: function() {
        glmatrix_mat2d.invert(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for mutiply
     * @param  {clay.Matrix2d} b
     * @return {clay.Matrix2d}
     */
    mul: function(b) {
        glmatrix_mat2d.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiplyLeft
     * @param  {clay.Matrix2d} a
     * @return {clay.Matrix2d}
     */
    mulLeft: function(b) {
        glmatrix_mat2d.mul(this.array, b.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply self and b
     * @param  {clay.Matrix2d} b
     * @return {clay.Matrix2d}
     */
    multiply: function(b) {
        glmatrix_mat2d.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply a and self, a is on the left
     * @param  {clay.Matrix2d} a
     * @return {clay.Matrix2d}
     */
    multiplyLeft: function(b) {
        glmatrix_mat2d.multiply(this.array, b.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian
     * @param  {number}   rad
     * @return {clay.Matrix2d}
     */
    rotate: function(rad) {
        glmatrix_mat2d.rotate(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self by s
     * @param  {clay.Vector2}  s
     * @return {clay.Matrix2d}
     */
    scale: function(s) {
        glmatrix_mat2d.scale(this.array, this.array, s.array);
        this._dirty = true;
        return this;
    },

    /**
     * Translate self by v
     * @param  {clay.Vector2}  v
     * @return {clay.Matrix2d}
     */
    translate: function(v) {
        glmatrix_mat2d.translate(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },

    toString: function() {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @return {clay.Matrix2d}
 */
Matrix2d.copy = function(out, a) {
    glmatrix_mat2d.copy(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2d} a
 * @return {number}
 */
Matrix2d.determinant = function(a) {
    return glmatrix_mat2d.determinant(a.array);
};

/**
 * @param  {clay.Matrix2d} out
 * @return {clay.Matrix2d}
 */
Matrix2d.identity = function(out) {
    glmatrix_mat2d.identity(out.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @return {clay.Matrix2d}
 */
Matrix2d.invert = function(out, a) {
    glmatrix_mat2d.invert(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @param  {clay.Matrix2d} b
 * @return {clay.Matrix2d}
 */
Matrix2d.mul = function(out, a, b) {
    glmatrix_mat2d.mul(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @param  {clay.Matrix2d} b
 * @return {clay.Matrix2d}
 */
Matrix2d.multiply = Matrix2d.mul;

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @param  {number}   rad
 * @return {clay.Matrix2d}
 */
Matrix2d.rotate = function(out, a, rad) {
    glmatrix_mat2d.rotate(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @param  {clay.Vector2}  v
 * @return {clay.Matrix2d}
 */
Matrix2d.scale = function(out, a, v) {
    glmatrix_mat2d.scale(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix2d} out
 * @param  {clay.Matrix2d} a
 * @param  {clay.Vector2}  v
 * @return {clay.Matrix2d}
 */
Matrix2d.translate = function(out, a, v) {
    glmatrix_mat2d.translate(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Matrix2d = (Matrix2d);

;// CONCATENATED MODULE: ./node_modules/claygl/src/math/Matrix3.js


/**
 * @constructor
 * @alias clay.Matrix3
 */
var Matrix3 = function () {

    /**
     * Storage of Matrix3
     * @name array
     * @type {Float32Array}
     * @memberOf clay.Matrix3#
     */
    this.array = glmatrix_mat3.create();

    /**
     * @name _dirty
     * @type {boolean}
     * @memberOf clay.Matrix3#
     */
    this._dirty = true;
};

Matrix3.prototype = {

    constructor: Matrix3,

    /**
     * Set components from array
     * @param  {Float32Array|number[]} arr
     */
    setArray: function (arr) {
        for (var i = 0; i < this.array.length; i++) {
            this.array[i] = arr[i];
        }
        this._dirty = true;
        return this;
    },
    /**
     * Calculate the adjugate of self, in-place
     * @return {clay.Matrix3}
     */
    adjoint: function () {
        glmatrix_mat3.adjoint(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Clone a new Matrix3
     * @return {clay.Matrix3}
     */
    clone: function () {
        return (new Matrix3()).copy(this);
    },

    /**
     * Copy from b
     * @param  {clay.Matrix3} b
     * @return {clay.Matrix3}
     */
    copy: function (b) {
        glmatrix_mat3.copy(this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculate matrix determinant
     * @return {number}
     */
    determinant: function () {
        return glmatrix_mat3.determinant(this.array);
    },

    /**
     * Copy the values from Matrix2d a
     * @param  {clay.Matrix2d} a
     * @return {clay.Matrix3}
     */
    fromMat2d: function (a) {
        glmatrix_mat3.fromMat2d(this.array, a.array);
        this._dirty = true;
        return this;
    },

    /**
     * Copies the upper-left 3x3 values of Matrix4
     * @param  {clay.Matrix4} a
     * @return {clay.Matrix3}
     */
    fromMat4: function (a) {
        glmatrix_mat3.fromMat4(this.array, a.array);
        this._dirty = true;
        return this;
    },

    /**
     * Calculates a rotation matrix from the given quaternion
     * @param  {clay.Quaternion} q
     * @return {clay.Matrix3}
     */
    fromQuat: function (q) {
        glmatrix_mat3.fromQuat(this.array, q.array);
        this._dirty = true;
        return this;
    },

    /**
     * Set to a identity matrix
     * @return {clay.Matrix3}
     */
    identity: function () {
        glmatrix_mat3.identity(this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Invert self
     * @return {clay.Matrix3}
     */
    invert: function () {
        glmatrix_mat3.invert(this.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for mutiply
     * @param  {clay.Matrix3} b
     * @return {clay.Matrix3}
     */
    mul: function (b) {
        glmatrix_mat3.mul(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Alias for multiplyLeft
     * @param  {clay.Matrix3} a
     * @return {clay.Matrix3}
     */
    mulLeft: function (a) {
        glmatrix_mat3.mul(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply self and b
     * @param  {clay.Matrix3} b
     * @return {clay.Matrix3}
     */
    multiply: function (b) {
        glmatrix_mat3.multiply(this.array, this.array, b.array);
        this._dirty = true;
        return this;
    },

    /**
     * Multiply a and self, a is on the left
     * @param  {clay.Matrix3} a
     * @return {clay.Matrix3}
     */
    multiplyLeft: function (a) {
        glmatrix_mat3.multiply(this.array, a.array, this.array);
        this._dirty = true;
        return this;
    },

    /**
     * Rotate self by a given radian
     * @param  {number}   rad
     * @return {clay.Matrix3}
     */
    rotate: function (rad) {
        glmatrix_mat3.rotate(this.array, this.array, rad);
        this._dirty = true;
        return this;
    },

    /**
     * Scale self by s
     * @param  {clay.Vector2}  s
     * @return {clay.Matrix3}
     */
    scale: function (v) {
        glmatrix_mat3.scale(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },

    /**
     * Translate self by v
     * @param  {clay.Vector2}  v
     * @return {clay.Matrix3}
     */
    translate: function (v) {
        glmatrix_mat3.translate(this.array, this.array, v.array);
        this._dirty = true;
        return this;
    },
    /**
     * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
     * @param {clay.Matrix4} a
     */
    normalFromMat4: function (a) {
        glmatrix_mat3.normalFromMat4(this.array, a.array);
        this._dirty = true;
        return this;
    },

    /**
     * Transpose self, in-place.
     * @return {clay.Matrix2}
     */
    transpose: function () {
        glmatrix_mat3.transpose(this.array, this.array);
        this._dirty = true;
        return this;
    },

    toString: function () {
        return '[' + Array.prototype.join.call(this.array, ',') + ']';
    },

    toArray: function () {
        return Array.prototype.slice.call(this.array);
    }
};
/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @return {clay.Matrix3}
 */
Matrix3.adjoint = function (out, a) {
    glmatrix_mat3.adjoint(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @return {clay.Matrix3}
 */
Matrix3.copy = function (out, a) {
    glmatrix_mat3.copy(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} a
 * @return {number}
 */
Matrix3.determinant = function (a) {
    return glmatrix_mat3.determinant(a.array);
};

/**
 * @param  {clay.Matrix3} out
 * @return {clay.Matrix3}
 */
Matrix3.identity = function (out) {
    glmatrix_mat3.identity(out.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @return {clay.Matrix3}
 */
Matrix3.invert = function (out, a) {
    glmatrix_mat3.invert(out.array, a.array);
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @param  {clay.Matrix3} b
 * @return {clay.Matrix3}
 */
Matrix3.mul = function (out, a, b) {
    glmatrix_mat3.mul(out.array, a.array, b.array);
    out._dirty = true;
    return out;
};

/**
 * @function
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @param  {clay.Matrix3} b
 * @return {clay.Matrix3}
 */
Matrix3.multiply = Matrix3.mul;

/**
 * @param  {clay.Matrix3}  out
 * @param  {clay.Matrix2d} a
 * @return {clay.Matrix3}
 */
Matrix3.fromMat2d = function (out, a) {
    glmatrix_mat3.fromMat2d(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix3}
 */
Matrix3.fromMat4 = function (out, a) {
    glmatrix_mat3.fromMat4(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3}    out
 * @param  {clay.Quaternion} a
 * @return {clay.Matrix3}
 */
Matrix3.fromQuat = function (out, q) {
    glmatrix_mat3.fromQuat(out.array, q.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix4} a
 * @return {clay.Matrix3}
 */
Matrix3.normalFromMat4 = function (out, a) {
    glmatrix_mat3.normalFromMat4(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @param  {number}  rad
 * @return {clay.Matrix3}
 */
Matrix3.rotate = function (out, a, rad) {
    glmatrix_mat3.rotate(out.array, a.array, rad);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @param  {clay.Vector2} v
 * @return {clay.Matrix3}
 */
Matrix3.scale = function (out, a, v) {
    glmatrix_mat3.scale(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @return {clay.Matrix3}
 */
Matrix3.transpose = function (out, a) {
    glmatrix_mat3.transpose(out.array, a.array);
    out._dirty = true;
    return out;
};

/**
 * @param  {clay.Matrix3} out
 * @param  {clay.Matrix3} a
 * @param  {clay.Vector2} v
 * @return {clay.Matrix3}
 */
Matrix3.translate = function (out, a, v) {
    glmatrix_mat3.translate(out.array, a.array, v.array);
    out._dirty = true;
    return out;
};

/* harmony default export */ const math_Matrix3 = (Matrix3);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/animation/easing.js
var easing = {
    linear: function (k) {
        return k;
    },
    quadraticIn: function (k) {
        return k * k;
    },
    quadraticOut: function (k) {
        return k * (2 - k);
    },
    quadraticInOut: function (k) {
        if ((k *= 2) < 1) {
            return 0.5 * k * k;
        }
        return -0.5 * (--k * (k - 2) - 1);
    },
    cubicIn: function (k) {
        return k * k * k;
    },
    cubicOut: function (k) {
        return --k * k * k + 1;
    },
    cubicInOut: function (k) {
        if ((k *= 2) < 1) {
            return 0.5 * k * k * k;
        }
        return 0.5 * ((k -= 2) * k * k + 2);
    },
    quarticIn: function (k) {
        return k * k * k * k;
    },
    quarticOut: function (k) {
        return 1 - (--k * k * k * k);
    },
    quarticInOut: function (k) {
        if ((k *= 2) < 1) {
            return 0.5 * k * k * k * k;
        }
        return -0.5 * ((k -= 2) * k * k * k - 2);
    },
    quinticIn: function (k) {
        return k * k * k * k * k;
    },
    quinticOut: function (k) {
        return --k * k * k * k * k + 1;
    },
    quinticInOut: function (k) {
        if ((k *= 2) < 1) {
            return 0.5 * k * k * k * k * k;
        }
        return 0.5 * ((k -= 2) * k * k * k * k + 2);
    },
    sinusoidalIn: function (k) {
        return 1 - Math.cos(k * Math.PI / 2);
    },
    sinusoidalOut: function (k) {
        return Math.sin(k * Math.PI / 2);
    },
    sinusoidalInOut: function (k) {
        return 0.5 * (1 - Math.cos(Math.PI * k));
    },
    exponentialIn: function (k) {
        return k === 0 ? 0 : Math.pow(1024, k - 1);
    },
    exponentialOut: function (k) {
        return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
    },
    exponentialInOut: function (k) {
        if (k === 0) {
            return 0;
        }
        if (k === 1) {
            return 1;
        }
        if ((k *= 2) < 1) {
            return 0.5 * Math.pow(1024, k - 1);
        }
        return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
    },
    circularIn: function (k) {
        return 1 - Math.sqrt(1 - k * k);
    },
    circularOut: function (k) {
        return Math.sqrt(1 - (--k * k));
    },
    circularInOut: function (k) {
        if ((k *= 2) < 1) {
            return -0.5 * (Math.sqrt(1 - k * k) - 1);
        }
        return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
    },
    elasticIn: function (k) {
        var s;
        var a = 0.1;
        var p = 0.4;
        if (k === 0) {
            return 0;
        }
        if (k === 1) {
            return 1;
        }
        if (!a || a < 1) {
            a = 1;
            s = p / 4;
        }
        else {
            s = p * Math.asin(1 / a) / (2 * Math.PI);
        }
        return -(a * Math.pow(2, 10 * (k -= 1))
            * Math.sin((k - s) * (2 * Math.PI) / p));
    },
    elasticOut: function (k) {
        var s;
        var a = 0.1;
        var p = 0.4;
        if (k === 0) {
            return 0;
        }
        if (k === 1) {
            return 1;
        }
        if (!a || a < 1) {
            a = 1;
            s = p / 4;
        }
        else {
            s = p * Math.asin(1 / a) / (2 * Math.PI);
        }
        return (a * Math.pow(2, -10 * k)
            * Math.sin((k - s) * (2 * Math.PI) / p) + 1);
    },
    elasticInOut: function (k) {
        var s;
        var a = 0.1;
        var p = 0.4;
        if (k === 0) {
            return 0;
        }
        if (k === 1) {
            return 1;
        }
        if (!a || a < 1) {
            a = 1;
            s = p / 4;
        }
        else {
            s = p * Math.asin(1 / a) / (2 * Math.PI);
        }
        if ((k *= 2) < 1) {
            return -0.5 * (a * Math.pow(2, 10 * (k -= 1))
                * Math.sin((k - s) * (2 * Math.PI) / p));
        }
        return a * Math.pow(2, -10 * (k -= 1))
            * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
    },
    backIn: function (k) {
        var s = 1.70158;
        return k * k * ((s + 1) * k - s);
    },
    backOut: function (k) {
        var s = 1.70158;
        return --k * k * ((s + 1) * k + s) + 1;
    },
    backInOut: function (k) {
        var s = 1.70158 * 1.525;
        if ((k *= 2) < 1) {
            return 0.5 * (k * k * ((s + 1) * k - s));
        }
        return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
    },
    bounceIn: function (k) {
        return 1 - easing.bounceOut(1 - k);
    },
    bounceOut: function (k) {
        if (k < (1 / 2.75)) {
            return 7.5625 * k * k;
        }
        else if (k < (2 / 2.75)) {
            return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75;
        }
        else if (k < (2.5 / 2.75)) {
            return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375;
        }
        else {
            return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375;
        }
    },
    bounceInOut: function (k) {
        if (k < 0.5) {
            return easing.bounceIn(k * 2) * 0.5;
        }
        return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
    }
};
/* harmony default export */ const animation_easing = (easing);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/animation/Clip.js

var Clip = (function () {
    function Clip(opts) {
        this._initialized = false;
        this._startTime = 0;
        this._pausedTime = 0;
        this._paused = false;
        this._life = opts.life || 1000;
        this._delay = opts.delay || 0;
        this.loop = opts.loop == null ? false : opts.loop;
        this.gap = opts.gap || 0;
        this.easing = opts.easing || 'linear';
        this.onframe = opts.onframe;
        this.ondestroy = opts.ondestroy;
        this.onrestart = opts.onrestart;
    }
    Clip.prototype.step = function (globalTime, deltaTime) {
        if (!this._initialized) {
            this._startTime = globalTime + this._delay;
            this._initialized = true;
        }
        if (this._paused) {
            this._pausedTime += deltaTime;
            return;
        }
        var percent = (globalTime - this._startTime - this._pausedTime) / this._life;
        if (percent < 0) {
            percent = 0;
        }
        percent = Math.min(percent, 1);
        var easing = this.easing;
        var easingFunc = typeof easing === 'string'
            ? animation_easing[easing] : easing;
        var schedule = typeof easingFunc === 'function'
            ? easingFunc(percent)
            : percent;
        this.onframe && this.onframe(schedule);
        if (percent === 1) {
            if (this.loop) {
                this._restart(globalTime);
                this.onrestart && this.onrestart();
            }
            else {
                return true;
            }
        }
        return false;
    };
    Clip.prototype._restart = function (globalTime) {
        var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
        this._startTime = globalTime - remainder + this.gap;
        this._pausedTime = 0;
    };
    Clip.prototype.pause = function () {
        this._paused = true;
    };
    Clip.prototype.resume = function () {
        this._paused = false;
    };
    return Clip;
}());
/* harmony default export */ const animation_Clip = (Clip);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/tool/color.js

var color_kCSSColorTable = {
    'transparent': [0, 0, 0, 0], 'aliceblue': [240, 248, 255, 1],
    'antiquewhite': [250, 235, 215, 1], 'aqua': [0, 255, 255, 1],
    'aquamarine': [127, 255, 212, 1], 'azure': [240, 255, 255, 1],
    'beige': [245, 245, 220, 1], 'bisque': [255, 228, 196, 1],
    'black': [0, 0, 0, 1], 'blanchedalmond': [255, 235, 205, 1],
    'blue': [0, 0, 255, 1], 'blueviolet': [138, 43, 226, 1],
    'brown': [165, 42, 42, 1], 'burlywood': [222, 184, 135, 1],
    'cadetblue': [95, 158, 160, 1], 'chartreuse': [127, 255, 0, 1],
    'chocolate': [210, 105, 30, 1], 'coral': [255, 127, 80, 1],
    'cornflowerblue': [100, 149, 237, 1], 'cornsilk': [255, 248, 220, 1],
    'crimson': [220, 20, 60, 1], 'cyan': [0, 255, 255, 1],
    'darkblue': [0, 0, 139, 1], 'darkcyan': [0, 139, 139, 1],
    'darkgoldenrod': [184, 134, 11, 1], 'darkgray': [169, 169, 169, 1],
    'darkgreen': [0, 100, 0, 1], 'darkgrey': [169, 169, 169, 1],
    'darkkhaki': [189, 183, 107, 1], 'darkmagenta': [139, 0, 139, 1],
    'darkolivegreen': [85, 107, 47, 1], 'darkorange': [255, 140, 0, 1],
    'darkorchid': [153, 50, 204, 1], 'darkred': [139, 0, 0, 1],
    'darksalmon': [233, 150, 122, 1], 'darkseagreen': [143, 188, 143, 1],
    'darkslateblue': [72, 61, 139, 1], 'darkslategray': [47, 79, 79, 1],
    'darkslategrey': [47, 79, 79, 1], 'darkturquoise': [0, 206, 209, 1],
    'darkviolet': [148, 0, 211, 1], 'deeppink': [255, 20, 147, 1],
    'deepskyblue': [0, 191, 255, 1], 'dimgray': [105, 105, 105, 1],
    'dimgrey': [105, 105, 105, 1], 'dodgerblue': [30, 144, 255, 1],
    'firebrick': [178, 34, 34, 1], 'floralwhite': [255, 250, 240, 1],
    'forestgreen': [34, 139, 34, 1], 'fuchsia': [255, 0, 255, 1],
    'gainsboro': [220, 220, 220, 1], 'ghostwhite': [248, 248, 255, 1],
    'gold': [255, 215, 0, 1], 'goldenrod': [218, 165, 32, 1],
    'gray': [128, 128, 128, 1], 'green': [0, 128, 0, 1],
    'greenyellow': [173, 255, 47, 1], 'grey': [128, 128, 128, 1],
    'honeydew': [240, 255, 240, 1], 'hotpink': [255, 105, 180, 1],
    'indianred': [205, 92, 92, 1], 'indigo': [75, 0, 130, 1],
    'ivory': [255, 255, 240, 1], 'khaki': [240, 230, 140, 1],
    'lavender': [230, 230, 250, 1], 'lavenderblush': [255, 240, 245, 1],
    'lawngreen': [124, 252, 0, 1], 'lemonchiffon': [255, 250, 205, 1],
    'lightblue': [173, 216, 230, 1], 'lightcoral': [240, 128, 128, 1],
    'lightcyan': [224, 255, 255, 1], 'lightgoldenrodyellow': [250, 250, 210, 1],
    'lightgray': [211, 211, 211, 1], 'lightgreen': [144, 238, 144, 1],
    'lightgrey': [211, 211, 211, 1], 'lightpink': [255, 182, 193, 1],
    'lightsalmon': [255, 160, 122, 1], 'lightseagreen': [32, 178, 170, 1],
    'lightskyblue': [135, 206, 250, 1], 'lightslategray': [119, 136, 153, 1],
    'lightslategrey': [119, 136, 153, 1], 'lightsteelblue': [176, 196, 222, 1],
    'lightyellow': [255, 255, 224, 1], 'lime': [0, 255, 0, 1],
    'limegreen': [50, 205, 50, 1], 'linen': [250, 240, 230, 1],
    'magenta': [255, 0, 255, 1], 'maroon': [128, 0, 0, 1],
    'mediumaquamarine': [102, 205, 170, 1], 'mediumblue': [0, 0, 205, 1],
    'mediumorchid': [186, 85, 211, 1], 'mediumpurple': [147, 112, 219, 1],
    'mediumseagreen': [60, 179, 113, 1], 'mediumslateblue': [123, 104, 238, 1],
    'mediumspringgreen': [0, 250, 154, 1], 'mediumturquoise': [72, 209, 204, 1],
    'mediumvioletred': [199, 21, 133, 1], 'midnightblue': [25, 25, 112, 1],
    'mintcream': [245, 255, 250, 1], 'mistyrose': [255, 228, 225, 1],
    'moccasin': [255, 228, 181, 1], 'navajowhite': [255, 222, 173, 1],
    'navy': [0, 0, 128, 1], 'oldlace': [253, 245, 230, 1],
    'olive': [128, 128, 0, 1], 'olivedrab': [107, 142, 35, 1],
    'orange': [255, 165, 0, 1], 'orangered': [255, 69, 0, 1],
    'orchid': [218, 112, 214, 1], 'palegoldenrod': [238, 232, 170, 1],
    'palegreen': [152, 251, 152, 1], 'paleturquoise': [175, 238, 238, 1],
    'palevioletred': [219, 112, 147, 1], 'papayawhip': [255, 239, 213, 1],
    'peachpuff': [255, 218, 185, 1], 'peru': [205, 133, 63, 1],
    'pink': [255, 192, 203, 1], 'plum': [221, 160, 221, 1],
    'powderblue': [176, 224, 230, 1], 'purple': [128, 0, 128, 1],
    'red': [255, 0, 0, 1], 'rosybrown': [188, 143, 143, 1],
    'royalblue': [65, 105, 225, 1], 'saddlebrown': [139, 69, 19, 1],
    'salmon': [250, 128, 114, 1], 'sandybrown': [244, 164, 96, 1],
    'seagreen': [46, 139, 87, 1], 'seashell': [255, 245, 238, 1],
    'sienna': [160, 82, 45, 1], 'silver': [192, 192, 192, 1],
    'skyblue': [135, 206, 235, 1], 'slateblue': [106, 90, 205, 1],
    'slategray': [112, 128, 144, 1], 'slategrey': [112, 128, 144, 1],
    'snow': [255, 250, 250, 1], 'springgreen': [0, 255, 127, 1],
    'steelblue': [70, 130, 180, 1], 'tan': [210, 180, 140, 1],
    'teal': [0, 128, 128, 1], 'thistle': [216, 191, 216, 1],
    'tomato': [255, 99, 71, 1], 'turquoise': [64, 224, 208, 1],
    'violet': [238, 130, 238, 1], 'wheat': [245, 222, 179, 1],
    'white': [255, 255, 255, 1], 'whitesmoke': [245, 245, 245, 1],
    'yellow': [255, 255, 0, 1], 'yellowgreen': [154, 205, 50, 1]
};
function color_clampCssByte(i) {
    i = Math.round(i);
    return i < 0 ? 0 : i > 255 ? 255 : i;
}
function color_clampCssAngle(i) {
    i = Math.round(i);
    return i < 0 ? 0 : i > 360 ? 360 : i;
}
function color_clampCssFloat(f) {
    return f < 0 ? 0 : f > 1 ? 1 : f;
}
function color_parseCssInt(val) {
    var str = val;
    if (str.length && str.charAt(str.length - 1) === '%') {
        return color_clampCssByte(parseFloat(str) / 100 * 255);
    }
    return color_clampCssByte(parseInt(str, 10));
}
function color_parseCssFloat(val) {
    var str = val;
    if (str.length && str.charAt(str.length - 1) === '%') {
        return color_clampCssFloat(parseFloat(str) / 100);
    }
    return color_clampCssFloat(parseFloat(str));
}
function color_cssHueToRgb(m1, m2, h) {
    if (h < 0) {
        h += 1;
    }
    else if (h > 1) {
        h -= 1;
    }
    if (h * 6 < 1) {
        return m1 + (m2 - m1) * h * 6;
    }
    if (h * 2 < 1) {
        return m2;
    }
    if (h * 3 < 2) {
        return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    }
    return m1;
}
function color_lerpNumber(a, b, p) {
    return a + (b - a) * p;
}
function color_setRgba(out, r, g, b, a) {
    out[0] = r;
    out[1] = g;
    out[2] = b;
    out[3] = a;
    return out;
}
function color_copyRgba(out, a) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    return out;
}
var color_colorCache = new lib_core_LRU(20);
var color_lastRemovedArr = null;
function color_putToCache(colorStr, rgbaArr) {
    if (color_lastRemovedArr) {
        color_copyRgba(color_lastRemovedArr, rgbaArr);
    }
    color_lastRemovedArr = color_colorCache.put(colorStr, color_lastRemovedArr || (rgbaArr.slice()));
}
function parse(colorStr, rgbaArr) {
    if (!colorStr) {
        return;
    }
    rgbaArr = rgbaArr || [];
    var cached = color_colorCache.get(colorStr);
    if (cached) {
        return color_copyRgba(rgbaArr, cached);
    }
    colorStr = colorStr + '';
    var str = colorStr.replace(/ /g, '').toLowerCase();
    if (str in color_kCSSColorTable) {
        color_copyRgba(rgbaArr, color_kCSSColorTable[str]);
        color_putToCache(colorStr, rgbaArr);
        return rgbaArr;
    }
    var strLen = str.length;
    if (str.charAt(0) === '#') {
        if (strLen === 4 || strLen === 5) {
            var iv = parseInt(str.slice(1, 4), 16);
            if (!(iv >= 0 && iv <= 0xfff)) {
                color_setRgba(rgbaArr, 0, 0, 0, 1);
                return;
            }
            color_setRgba(rgbaArr, ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), (iv & 0xf0) | ((iv & 0xf0) >> 4), (iv & 0xf) | ((iv & 0xf) << 4), strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1);
            color_putToCache(colorStr, rgbaArr);
            return rgbaArr;
        }
        else if (strLen === 7 || strLen === 9) {
            var iv = parseInt(str.slice(1, 7), 16);
            if (!(iv >= 0 && iv <= 0xffffff)) {
                color_setRgba(rgbaArr, 0, 0, 0, 1);
                return;
            }
            color_setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1);
            color_putToCache(colorStr, rgbaArr);
            return rgbaArr;
        }
        return;
    }
    var op = str.indexOf('(');
    var ep = str.indexOf(')');
    if (op !== -1 && ep + 1 === strLen) {
        var fname = str.substr(0, op);
        var params = str.substr(op + 1, ep - (op + 1)).split(',');
        var alpha = 1;
        switch (fname) {
            case 'rgba':
                if (params.length !== 4) {
                    return params.length === 3
                        ? color_setRgba(rgbaArr, +params[0], +params[1], +params[2], 1)
                        : color_setRgba(rgbaArr, 0, 0, 0, 1);
                }
                alpha = color_parseCssFloat(params.pop());
            case 'rgb':
                if (params.length !== 3) {
                    color_setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                color_setRgba(rgbaArr, color_parseCssInt(params[0]), color_parseCssInt(params[1]), color_parseCssInt(params[2]), alpha);
                color_putToCache(colorStr, rgbaArr);
                return rgbaArr;
            case 'hsla':
                if (params.length !== 4) {
                    color_setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                params[3] = color_parseCssFloat(params[3]);
                color_hsla2rgba(params, rgbaArr);
                color_putToCache(colorStr, rgbaArr);
                return rgbaArr;
            case 'hsl':
                if (params.length !== 3) {
                    color_setRgba(rgbaArr, 0, 0, 0, 1);
                    return;
                }
                color_hsla2rgba(params, rgbaArr);
                color_putToCache(colorStr, rgbaArr);
                return rgbaArr;
            default:
                return;
        }
    }
    color_setRgba(rgbaArr, 0, 0, 0, 1);
    return;
}
function color_hsla2rgba(hsla, rgba) {
    var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360;
    var s = color_parseCssFloat(hsla[1]);
    var l = color_parseCssFloat(hsla[2]);
    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
    var m1 = l * 2 - m2;
    rgba = rgba || [];
    color_setRgba(rgba, color_clampCssByte(color_cssHueToRgb(m1, m2, h + 1 / 3) * 255), color_clampCssByte(color_cssHueToRgb(m1, m2, h) * 255), color_clampCssByte(color_cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1);
    if (hsla.length === 4) {
        rgba[3] = hsla[3];
    }
    return rgba;
}
function color_rgba2hsla(rgba) {
    if (!rgba) {
        return;
    }
    var R = rgba[0] / 255;
    var G = rgba[1] / 255;
    var B = rgba[2] / 255;
    var vMin = Math.min(R, G, B);
    var vMax = Math.max(R, G, B);
    var delta = vMax - vMin;
    var L = (vMax + vMin) / 2;
    var H;
    var S;
    if (delta === 0) {
        H = 0;
        S = 0;
    }
    else {
        if (L < 0.5) {
            S = delta / (vMax + vMin);
        }
        else {
            S = delta / (2 - vMax - vMin);
        }
        var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta;
        var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta;
        var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta;
        if (R === vMax) {
            H = deltaB - deltaG;
        }
        else if (G === vMax) {
            H = (1 / 3) + deltaR - deltaB;
        }
        else if (B === vMax) {
            H = (2 / 3) + deltaG - deltaR;
        }
        if (H < 0) {
            H += 1;
        }
        if (H > 1) {
            H -= 1;
        }
    }
    var hsla = [H * 360, S, L];
    if (rgba[3] != null) {
        hsla.push(rgba[3]);
    }
    return hsla;
}
function lift(color, level) {
    var colorArr = parse(color);
    if (colorArr) {
        for (var i = 0; i < 3; i++) {
            if (level < 0) {
                colorArr[i] = colorArr[i] * (1 - level) | 0;
            }
            else {
                colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0;
            }
            if (colorArr[i] > 255) {
                colorArr[i] = 255;
            }
            else if (colorArr[i] < 0) {
                colorArr[i] = 0;
            }
        }
        return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
    }
}
function toHex(color) {
    var colorArr = parse(color);
    if (colorArr) {
        return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1);
    }
}
function fastLerp(normalizedValue, colors, out) {
    if (!(colors && colors.length)
        || !(normalizedValue >= 0 && normalizedValue <= 1)) {
        return;
    }
    out = out || [];
    var value = normalizedValue * (colors.length - 1);
    var leftIndex = Math.floor(value);
    var rightIndex = Math.ceil(value);
    var leftColor = colors[leftIndex];
    var rightColor = colors[rightIndex];
    var dv = value - leftIndex;
    out[0] = color_clampCssByte(color_lerpNumber(leftColor[0], rightColor[0], dv));
    out[1] = color_clampCssByte(color_lerpNumber(leftColor[1], rightColor[1], dv));
    out[2] = color_clampCssByte(color_lerpNumber(leftColor[2], rightColor[2], dv));
    out[3] = color_clampCssFloat(color_lerpNumber(leftColor[3], rightColor[3], dv));
    return out;
}
var fastMapToColor = fastLerp;
function lerp(normalizedValue, colors, fullOutput) {
    if (!(colors && colors.length)
        || !(normalizedValue >= 0 && normalizedValue <= 1)) {
        return;
    }
    var value = normalizedValue * (colors.length - 1);
    var leftIndex = Math.floor(value);
    var rightIndex = Math.ceil(value);
    var leftColor = parse(colors[leftIndex]);
    var rightColor = parse(colors[rightIndex]);
    var dv = value - leftIndex;
    var color = stringify([
        color_clampCssByte(color_lerpNumber(leftColor[0], rightColor[0], dv)),
        color_clampCssByte(color_lerpNumber(leftColor[1], rightColor[1], dv)),
        color_clampCssByte(color_lerpNumber(leftColor[2], rightColor[2], dv)),
        color_clampCssFloat(color_lerpNumber(leftColor[3], rightColor[3], dv))
    ], 'rgba');
    return fullOutput
        ? {
            color: color,
            leftIndex: leftIndex,
            rightIndex: rightIndex,
            value: value
        }
        : color;
}
var mapToColor = lerp;
function modifyHSL(color, h, s, l) {
    var colorArr = parse(color);
    if (color) {
        colorArr = color_rgba2hsla(colorArr);
        h != null && (colorArr[0] = color_clampCssAngle(h));
        s != null && (colorArr[1] = color_parseCssFloat(s));
        l != null && (colorArr[2] = color_parseCssFloat(l));
        return stringify(color_hsla2rgba(colorArr), 'rgba');
    }
}
function modifyAlpha(color, alpha) {
    var colorArr = parse(color);
    if (colorArr && alpha != null) {
        colorArr[3] = color_clampCssFloat(alpha);
        return stringify(colorArr, 'rgba');
    }
}
function stringify(arrColor, type) {
    if (!arrColor || !arrColor.length) {
        return;
    }
    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
        colorStr += ',' + arrColor[3];
    }
    return type + '(' + colorStr + ')';
}
function lum(color, backgroundLum) {
    var arr = parse(color);
    return arr
        ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255
            + (1 - arr[3]) * backgroundLum
        : 0;
}
function random() {
    var r = Math.round(Math.random() * 255);
    var g = Math.round(Math.random() * 255);
    var b = Math.round(Math.random() * 255);
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/util.js
var BUILTIN_OBJECT = {
    '[object Function]': true,
    '[object RegExp]': true,
    '[object Date]': true,
    '[object Error]': true,
    '[object CanvasGradient]': true,
    '[object CanvasPattern]': true,
    '[object Image]': true,
    '[object Canvas]': true
};
var TYPED_ARRAY = {
    '[object Int8Array]': true,
    '[object Uint8Array]': true,
    '[object Uint8ClampedArray]': true,
    '[object Int16Array]': true,
    '[object Uint16Array]': true,
    '[object Int32Array]': true,
    '[object Uint32Array]': true,
    '[object Float32Array]': true,
    '[object Float64Array]': true
};
var objToString = Object.prototype.toString;
var arrayProto = Array.prototype;
var util_nativeForEach = arrayProto.forEach;
var nativeFilter = arrayProto.filter;
var nativeSlice = arrayProto.slice;
var nativeMap = arrayProto.map;
var ctorFunction = function () { }.constructor;
var protoFunction = ctorFunction ? ctorFunction.prototype : null;
var methods = {};
function $override(name, fn) {
    methods[name] = fn;
}
var idStart = 0x0907;
function util_guid() {
    return idStart++;
}
function logError() {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
    }
    if (typeof console !== 'undefined') {
        console.error.apply(console, args);
    }
}
function clone(source) {
    if (source == null || typeof source !== 'object') {
        return source;
    }
    var result = source;
    var typeStr = objToString.call(source);
    if (typeStr === '[object Array]') {
        if (!isPrimitive(source)) {
            result = [];
            for (var i = 0, len = source.length; i < len; i++) {
                result[i] = clone(source[i]);
            }
        }
    }
    else if (TYPED_ARRAY[typeStr]) {
        if (!isPrimitive(source)) {
            var Ctor = source.constructor;
            if (Ctor.from) {
                result = Ctor.from(source);
            }
            else {
                result = new Ctor(source.length);
                for (var i = 0, len = source.length; i < len; i++) {
                    result[i] = clone(source[i]);
                }
            }
        }
    }
    else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
        result = {};
        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                result[key] = clone(source[key]);
            }
        }
    }
    return result;
}
function merge(target, source, overwrite) {
    if (!isObject(source) || !isObject(target)) {
        return overwrite ? clone(source) : target;
    }
    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            var targetProp = target[key];
            var sourceProp = source[key];
            if (isObject(sourceProp)
                && isObject(targetProp)
                && !isArray(sourceProp)
                && !isArray(targetProp)
                && !isDom(sourceProp)
                && !isDom(targetProp)
                && !isBuiltInObject(sourceProp)
                && !isBuiltInObject(targetProp)
                && !isPrimitive(sourceProp)
                && !isPrimitive(targetProp)) {
                merge(targetProp, sourceProp, overwrite);
            }
            else if (overwrite || !(key in target)) {
                target[key] = clone(source[key]);
            }
        }
    }
    return target;
}
function mergeAll(targetAndSources, overwrite) {
    var result = targetAndSources[0];
    for (var i = 1, len = targetAndSources.length; i < len; i++) {
        result = merge(result, targetAndSources[i], overwrite);
    }
    return result;
}
function util_extend(target, source) {
    if (Object.assign) {
        Object.assign(target, source);
    }
    else {
        for (var key in source) {
            if (source.hasOwnProperty(key)) {
                target[key] = source[key];
            }
        }
    }
    return target;
}
function util_defaults(target, source, overlay) {
    var keysArr = keys(source);
    for (var i = 0; i < keysArr.length; i++) {
        var key = keysArr[i];
        if ((overlay ? source[key] != null : target[key] == null)) {
            target[key] = source[key];
        }
    }
    return target;
}
var createCanvas = function () {
    return methods.createCanvas();
};
methods.createCanvas = function () {
    return document.createElement('canvas');
};
function indexOf(array, value) {
    if (array) {
        if (array.indexOf) {
            return array.indexOf(value);
        }
        for (var i = 0, len = array.length; i < len; i++) {
            if (array[i] === value) {
                return i;
            }
        }
    }
    return -1;
}
function inherits(clazz, baseClazz) {
    var clazzPrototype = clazz.prototype;
    function F() { }
    F.prototype = baseClazz.prototype;
    clazz.prototype = new F();
    for (var prop in clazzPrototype) {
        if (clazzPrototype.hasOwnProperty(prop)) {
            clazz.prototype[prop] = clazzPrototype[prop];
        }
    }
    clazz.prototype.constructor = clazz;
    clazz.superClass = baseClazz;
}
function mixin(target, source, override) {
    target = 'prototype' in target ? target.prototype : target;
    source = 'prototype' in source ? source.prototype : source;
    if (Object.getOwnPropertyNames) {
        var keyList = Object.getOwnPropertyNames(source);
        for (var i = 0; i < keyList.length; i++) {
            var key = keyList[i];
            if (key !== 'constructor') {
                if ((override ? source[key] != null : target[key] == null)) {
                    target[key] = source[key];
                }
            }
        }
    }
    else {
        util_defaults(target, source, override);
    }
}
function isArrayLike(data) {
    if (!data) {
        return false;
    }
    if (typeof data === 'string') {
        return false;
    }
    return typeof data.length === 'number';
}
function each(arr, cb, context) {
    if (!(arr && cb)) {
        return;
    }
    if (arr.forEach && arr.forEach === util_nativeForEach) {
        arr.forEach(cb, context);
    }
    else if (arr.length === +arr.length) {
        for (var i = 0, len = arr.length; i < len; i++) {
            cb.call(context, arr[i], i, arr);
        }
    }
    else {
        for (var key in arr) {
            if (arr.hasOwnProperty(key)) {
                cb.call(context, arr[key], key, arr);
            }
        }
    }
}
function map(arr, cb, context) {
    if (!arr) {
        return [];
    }
    if (!cb) {
        return slice(arr);
    }
    if (arr.map && arr.map === nativeMap) {
        return arr.map(cb, context);
    }
    else {
        var result = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            result.push(cb.call(context, arr[i], i, arr));
        }
        return result;
    }
}
function reduce(arr, cb, memo, context) {
    if (!(arr && cb)) {
        return;
    }
    for (var i = 0, len = arr.length; i < len; i++) {
        memo = cb.call(context, memo, arr[i], i, arr);
    }
    return memo;
}
function filter(arr, cb, context) {
    if (!arr) {
        return [];
    }
    if (!cb) {
        return slice(arr);
    }
    if (arr.filter && arr.filter === nativeFilter) {
        return arr.filter(cb, context);
    }
    else {
        var result = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            if (cb.call(context, arr[i], i, arr)) {
                result.push(arr[i]);
            }
        }
        return result;
    }
}
function find(arr, cb, context) {
    if (!(arr && cb)) {
        return;
    }
    for (var i = 0, len = arr.length; i < len; i++) {
        if (cb.call(context, arr[i], i, arr)) {
            return arr[i];
        }
    }
}
function keys(obj) {
    if (!obj) {
        return [];
    }
    if (Object.keys) {
        return Object.keys(obj);
    }
    var keyList = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            keyList.push(key);
        }
    }
    return keyList;
}
function bindPolyfill(func, context) {
    var args = [];
    for (var _i = 2; _i < arguments.length; _i++) {
        args[_i - 2] = arguments[_i];
    }
    return function () {
        return func.apply(context, args.concat(nativeSlice.call(arguments)));
    };
}
var bind = (protoFunction && isFunction(protoFunction.bind))
    ? protoFunction.call.bind(protoFunction.bind)
    : bindPolyfill;
function curry(func) {
    var args = [];
    for (var _i = 1; _i < arguments.length; _i++) {
        args[_i - 1] = arguments[_i];
    }
    return function () {
        return func.apply(this, args.concat(nativeSlice.call(arguments)));
    };
}

function isArray(value) {
    if (Array.isArray) {
        return Array.isArray(value);
    }
    return objToString.call(value) === '[object Array]';
}
function isFunction(value) {
    return typeof value === 'function';
}
function isString(value) {
    return typeof value === 'string';
}
function isStringSafe(value) {
    return objToString.call(value) === '[object String]';
}
function isNumber(value) {
    return typeof value === 'number';
}
function isObject(value) {
    var type = typeof value;
    return type === 'function' || (!!value && type === 'object');
}
function isBuiltInObject(value) {
    return !!BUILTIN_OBJECT[objToString.call(value)];
}
function isTypedArray(value) {
    return !!TYPED_ARRAY[objToString.call(value)];
}
function isDom(value) {
    return typeof value === 'object'
        && typeof value.nodeType === 'number'
        && typeof value.ownerDocument === 'object';
}
function isGradientObject(value) {
    return value.colorStops != null;
}
function isImagePatternObject(value) {
    return value.image != null;
}
function isRegExp(value) {
    return objToString.call(value) === '[object RegExp]';
}
function eqNaN(value) {
    return value !== value;
}
function core_util_retrieve() {
    var args = [];
    for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
    }
    for (var i = 0, len = args.length; i < len; i++) {
        if (args[i] != null) {
            return args[i];
        }
    }
}
function retrieve2(value0, value1) {
    return value0 != null
        ? value0
        : value1;
}
function retrieve3(value0, value1, value2) {
    return value0 != null
        ? value0
        : value1 != null
            ? value1
            : value2;
}
function slice(arr) {
    var args = [];
    for (var _i = 1; _i < arguments.length; _i++) {
        args[_i - 1] = arguments[_i];
    }
    return nativeSlice.apply(arr, args);
}
function normalizeCssArray(val) {
    if (typeof (val) === 'number') {
        return [val, val, val, val];
    }
    var len = val.length;
    if (len === 2) {
        return [val[0], val[1], val[0], val[1]];
    }
    else if (len === 3) {
        return [val[0], val[1], val[2], val[1]];
    }
    return val;
}
function assert(condition, message) {
    if (!condition) {
        throw new Error(message);
    }
}
function trim(str) {
    if (str == null) {
        return null;
    }
    else if (typeof str.trim === 'function') {
        return str.trim();
    }
    else {
        return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    }
}
var primitiveKey = '__ec_primitive__';
function setAsPrimitive(obj) {
    obj[primitiveKey] = true;
}
function isPrimitive(obj) {
    return obj[primitiveKey];
}
var HashMap = (function () {
    function HashMap(obj) {
        this.data = {};
        var isArr = isArray(obj);
        this.data = {};
        var thisMap = this;
        (obj instanceof HashMap)
            ? obj.each(visit)
            : (obj && each(obj, visit));
        function visit(value, key) {
            isArr ? thisMap.set(value, key) : thisMap.set(key, value);
        }
    }
    HashMap.prototype.get = function (key) {
        return this.data.hasOwnProperty(key) ? this.data[key] : null;
    };
    HashMap.prototype.set = function (key, value) {
        return (this.data[key] = value);
    };
    HashMap.prototype.each = function (cb, context) {
        for (var key in this.data) {
            if (this.data.hasOwnProperty(key)) {
                cb.call(context, this.data[key], key);
            }
        }
    };
    HashMap.prototype.keys = function () {
        return keys(this.data);
    };
    HashMap.prototype.removeKey = function (key) {
        delete this.data[key];
    };
    return HashMap;
}());

function createHashMap(obj) {
    return new HashMap(obj);
}
function concatArray(a, b) {
    var newArray = new a.constructor(a.length + b.length);
    for (var i = 0; i < a.length; i++) {
        newArray[i] = a[i];
    }
    var offset = a.length;
    for (var i = 0; i < b.length; i++) {
        newArray[i + offset] = b[i];
    }
    return newArray;
}
function createObject(proto, properties) {
    var obj;
    if (Object.create) {
        obj = Object.create(proto);
    }
    else {
        var StyleCtor = function () { };
        StyleCtor.prototype = proto;
        obj = new StyleCtor();
    }
    if (properties) {
        util_extend(obj, properties);
    }
    return obj;
}
function hasOwn(own, prop) {
    return own.hasOwnProperty(prop);
}
function util_noop() { }

;// CONCATENATED MODULE: ./node_modules/zrender/lib/animation/Animator.js



var arraySlice = Array.prototype.slice;
function interpolateNumber(p0, p1, percent) {
    return (p1 - p0) * percent + p0;
}
function step(p0, p1, percent) {
    return percent > 0.5 ? p1 : p0;
}
function interpolate1DArray(out, p0, p1, percent) {
    var len = p0.length;
    for (var i = 0; i < len; i++) {
        out[i] = interpolateNumber(p0[i], p1[i], percent);
    }
}
function interpolate2DArray(out, p0, p1, percent) {
    var len = p0.length;
    var len2 = len && p0[0].length;
    for (var i = 0; i < len; i++) {
        if (!out[i]) {
            out[i] = [];
        }
        for (var j = 0; j < len2; j++) {
            out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent);
        }
    }
}
function add1DArray(out, p0, p1, sign) {
    var len = p0.length;
    for (var i = 0; i < len; i++) {
        out[i] = p0[i] + p1[i] * sign;
    }
    return out;
}
function add2DArray(out, p0, p1, sign) {
    var len = p0.length;
    var len2 = len && p0[0].length;
    for (var i = 0; i < len; i++) {
        if (!out[i]) {
            out[i] = [];
        }
        for (var j = 0; j < len2; j++) {
            out[i][j] = p0[i][j] + p1[i][j] * sign;
        }
    }
    return out;
}
function fillArray(val0, val1, arrDim) {
    var arr0 = val0;
    var arr1 = val1;
    if (!arr0.push || !arr1.push) {
        return;
    }
    var arr0Len = arr0.length;
    var arr1Len = arr1.length;
    if (arr0Len !== arr1Len) {
        var isPreviousLarger = arr0Len > arr1Len;
        if (isPreviousLarger) {
            arr0.length = arr1Len;
        }
        else {
            for (var i = arr0Len; i < arr1Len; i++) {
                arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]));
            }
        }
    }
    var len2 = arr0[0] && arr0[0].length;
    for (var i = 0; i < arr0.length; i++) {
        if (arrDim === 1) {
            if (isNaN(arr0[i])) {
                arr0[i] = arr1[i];
            }
        }
        else {
            for (var j = 0; j < len2; j++) {
                if (isNaN(arr0[i][j])) {
                    arr0[i][j] = arr1[i][j];
                }
            }
        }
    }
}
function is1DArraySame(arr0, arr1) {
    var len = arr0.length;
    if (len !== arr1.length) {
        return false;
    }
    for (var i = 0; i < len; i++) {
        if (arr0[i] !== arr1[i]) {
            return false;
        }
    }
    return true;
}
function is2DArraySame(arr0, arr1) {
    var len = arr0.length;
    if (len !== arr1.length) {
        return false;
    }
    var len2 = arr0[0].length;
    for (var i = 0; i < len; i++) {
        for (var j = 0; j < len2; j++) {
            if (arr0[i][j] !== arr1[i][j]) {
                return false;
            }
        }
    }
    return true;
}
function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
    var v0 = (p2 - p0) * 0.5;
    var v1 = (p3 - p1) * 0.5;
    return (2 * (p1 - p2) + v0 + v1) * t3
        + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
        + v0 * t + p1;
}
function catmullRomInterpolate1DArray(out, p0, p1, p2, p3, t, t2, t3) {
    var len = p0.length;
    for (var i = 0; i < len; i++) {
        out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3);
    }
}
function catmullRomInterpolate2DArray(out, p0, p1, p2, p3, t, t2, t3) {
    var len = p0.length;
    var len2 = p0[0].length;
    for (var i = 0; i < len; i++) {
        if (!out[i]) {
            out[1] = [];
        }
        for (var j = 0; j < len2; j++) {
            out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3);
        }
    }
}
function cloneValue(value) {
    if (isArrayLike(value)) {
        var len = value.length;
        if (isArrayLike(value[0])) {
            var ret = [];
            for (var i = 0; i < len; i++) {
                ret.push(arraySlice.call(value[i]));
            }
            return ret;
        }
        return arraySlice.call(value);
    }
    return value;
}
function rgba2String(rgba) {
    rgba[0] = Math.floor(rgba[0]);
    rgba[1] = Math.floor(rgba[1]);
    rgba[2] = Math.floor(rgba[2]);
    return 'rgba(' + rgba.join(',') + ')';
}
function guessArrayDim(value) {
    return isArrayLike(value && value[0]) ? 2 : 1;
}
var tmpRgba = [0, 0, 0, 0];
var Track = (function () {
    function Track(propName) {
        this.keyframes = [];
        this.maxTime = 0;
        this.arrDim = 0;
        this.interpolable = true;
        this._needsSort = false;
        this._isAllValueEqual = true;
        this._lastFrame = 0;
        this._lastFramePercent = 0;
        this.propName = propName;
    }
    Track.prototype.isFinished = function () {
        return this._finished;
    };
    Track.prototype.setFinished = function () {
        this._finished = true;
        if (this._additiveTrack) {
            this._additiveTrack.setFinished();
        }
    };
    Track.prototype.needsAnimate = function () {
        return !this._isAllValueEqual && this.keyframes.length >= 2 && this.interpolable;
    };
    Track.prototype.getAdditiveTrack = function () {
        return this._additiveTrack;
    };
    Track.prototype.addKeyframe = function (time, value) {
        if (time >= this.maxTime) {
            this.maxTime = time;
        }
        else {
            this._needsSort = true;
        }
        var keyframes = this.keyframes;
        var len = keyframes.length;
        if (this.interpolable) {
            if (isArrayLike(value)) {
                var arrayDim = guessArrayDim(value);
                if (len > 0 && this.arrDim !== arrayDim) {
                    this.interpolable = false;
                    return;
                }
                if (arrayDim === 1 && typeof value[0] !== 'number'
                    || arrayDim === 2 && typeof value[0][0] !== 'number') {
                    this.interpolable = false;
                    return;
                }
                if (len > 0) {
                    var lastFrame = keyframes[len - 1];
                    if (this._isAllValueEqual) {
                        if (arrayDim === 1) {
                            if (!is1DArraySame(value, lastFrame.value)) {
                                this._isAllValueEqual = false;
                            }
                        }
                        else {
                            this._isAllValueEqual = false;
                        }
                    }
                }
                this.arrDim = arrayDim;
            }
            else {
                if (this.arrDim > 0) {
                    this.interpolable = false;
                    return;
                }
                if (typeof value === 'string') {
                    var colorArray = parse(value);
                    if (colorArray) {
                        value = colorArray;
                        this.isValueColor = true;
                    }
                    else {
                        this.interpolable = false;
                    }
                }
                else if (typeof value !== 'number' || isNaN(value)) {
                    this.interpolable = false;
                    return;
                }
                if (this._isAllValueEqual && len > 0) {
                    var lastFrame = keyframes[len - 1];
                    if (this.isValueColor && !is1DArraySame(lastFrame.value, value)) {
                        this._isAllValueEqual = false;
                    }
                    else if (lastFrame.value !== value) {
                        this._isAllValueEqual = false;
                    }
                }
            }
        }
        var kf = {
            time: time,
            value: value,
            percent: 0
        };
        this.keyframes.push(kf);
        return kf;
    };
    Track.prototype.prepare = function (additiveTrack) {
        var kfs = this.keyframes;
        if (this._needsSort) {
            kfs.sort(function (a, b) {
                return a.time - b.time;
            });
        }
        var arrDim = this.arrDim;
        var kfsLen = kfs.length;
        var lastKf = kfs[kfsLen - 1];
        for (var i = 0; i < kfsLen; i++) {
            kfs[i].percent = kfs[i].time / this.maxTime;
            if (arrDim > 0 && i !== kfsLen - 1) {
                fillArray(kfs[i].value, lastKf.value, arrDim);
            }
        }
        if (additiveTrack
            && this.needsAnimate()
            && additiveTrack.needsAnimate()
            && arrDim === additiveTrack.arrDim
            && this.isValueColor === additiveTrack.isValueColor
            && !additiveTrack._finished) {
            this._additiveTrack = additiveTrack;
            var startValue = kfs[0].value;
            for (var i = 0; i < kfsLen; i++) {
                if (arrDim === 0) {
                    if (this.isValueColor) {
                        kfs[i].additiveValue
                            = add1DArray([], kfs[i].value, startValue, -1);
                    }
                    else {
                        kfs[i].additiveValue = kfs[i].value - startValue;
                    }
                }
                else if (arrDim === 1) {
                    kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1);
                }
                else if (arrDim === 2) {
                    kfs[i].additiveValue = add2DArray([], kfs[i].value, startValue, -1);
                }
            }
        }
    };
    Track.prototype.step = function (target, percent) {
        if (this._finished) {
            return;
        }
        if (this._additiveTrack && this._additiveTrack._finished) {
            this._additiveTrack = null;
        }
        var isAdditive = this._additiveTrack != null;
        var valueKey = isAdditive ? 'additiveValue' : 'value';
        var keyframes = this.keyframes;
        var kfsNum = this.keyframes.length;
        var propName = this.propName;
        var arrDim = this.arrDim;
        var isValueColor = this.isValueColor;
        var frameIdx;
        if (percent < 0) {
            frameIdx = 0;
        }
        else if (percent < this._lastFramePercent) {
            var start = Math.min(this._lastFrame + 1, kfsNum - 1);
            for (frameIdx = start; frameIdx >= 0; frameIdx--) {
                if (keyframes[frameIdx].percent <= percent) {
                    break;
                }
            }
            frameIdx = Math.min(frameIdx, kfsNum - 2);
        }
        else {
            for (frameIdx = this._lastFrame; frameIdx < kfsNum; frameIdx++) {
                if (keyframes[frameIdx].percent > percent) {
                    break;
                }
            }
            frameIdx = Math.min(frameIdx - 1, kfsNum - 2);
        }
        var nextFrame = keyframes[frameIdx + 1];
        var frame = keyframes[frameIdx];
        if (!(frame && nextFrame)) {
            return;
        }
        this._lastFrame = frameIdx;
        this._lastFramePercent = percent;
        var range = (nextFrame.percent - frame.percent);
        if (range === 0) {
            return;
        }
        var w = (percent - frame.percent) / range;
        var targetArr = isAdditive ? this._additiveValue
            : (isValueColor ? tmpRgba : target[propName]);
        if ((arrDim > 0 || isValueColor) && !targetArr) {
            targetArr = this._additiveValue = [];
        }
        if (this.useSpline) {
            var p1 = keyframes[frameIdx][valueKey];
            var p0 = keyframes[frameIdx === 0 ? frameIdx : frameIdx - 1][valueKey];
            var p2 = keyframes[frameIdx > kfsNum - 2 ? kfsNum - 1 : frameIdx + 1][valueKey];
            var p3 = keyframes[frameIdx > kfsNum - 3 ? kfsNum - 1 : frameIdx + 2][valueKey];
            if (arrDim > 0) {
                arrDim === 1
                    ? catmullRomInterpolate1DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w)
                    : catmullRomInterpolate2DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w);
            }
            else if (isValueColor) {
                catmullRomInterpolate1DArray(targetArr, p0, p1, p2, p3, w, w * w, w * w * w);
                if (!isAdditive) {
                    target[propName] = rgba2String(targetArr);
                }
            }
            else {
                var value = void 0;
                if (!this.interpolable) {
                    value = p2;
                }
                else {
                    value = catmullRomInterpolate(p0, p1, p2, p3, w, w * w, w * w * w);
                }
                if (isAdditive) {
                    this._additiveValue = value;
                }
                else {
                    target[propName] = value;
                }
            }
        }
        else {
            if (arrDim > 0) {
                arrDim === 1
                    ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w)
                    : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);
            }
            else if (isValueColor) {
                interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);
                if (!isAdditive) {
                    target[propName] = rgba2String(targetArr);
                }
            }
            else {
                var value = void 0;
                if (!this.interpolable) {
                    value = step(frame[valueKey], nextFrame[valueKey], w);
                }
                else {
                    value = interpolateNumber(frame[valueKey], nextFrame[valueKey], w);
                }
                if (isAdditive) {
                    this._additiveValue = value;
                }
                else {
                    target[propName] = value;
                }
            }
        }
        if (isAdditive) {
            this._addToTarget(target);
        }
    };
    Track.prototype._addToTarget = function (target) {
        var arrDim = this.arrDim;
        var propName = this.propName;
        var additiveValue = this._additiveValue;
        if (arrDim === 0) {
            if (this.isValueColor) {
                parse(target[propName], tmpRgba);
                add1DArray(tmpRgba, tmpRgba, additiveValue, 1);
                target[propName] = rgba2String(tmpRgba);
            }
            else {
                target[propName] = target[propName] + additiveValue;
            }
        }
        else if (arrDim === 1) {
            add1DArray(target[propName], target[propName], additiveValue, 1);
        }
        else if (arrDim === 2) {
            add2DArray(target[propName], target[propName], additiveValue, 1);
        }
    };
    return Track;
}());
var Animator = (function () {
    function Animator(target, loop, additiveTo) {
        this._tracks = {};
        this._trackKeys = [];
        this._delay = 0;
        this._maxTime = 0;
        this._paused = false;
        this._started = 0;
        this._clip = null;
        this._target = target;
        this._loop = loop;
        if (loop && additiveTo) {
            logError('Can\' use additive animation on looped animation.');
            return;
        }
        this._additiveAnimators = additiveTo;
    }
    Animator.prototype.getTarget = function () {
        return this._target;
    };
    Animator.prototype.changeTarget = function (target) {
        this._target = target;
    };
    Animator.prototype.when = function (time, props) {
        return this.whenWithKeys(time, props, keys(props));
    };
    Animator.prototype.whenWithKeys = function (time, props, propNames) {
        var tracks = this._tracks;
        for (var i = 0; i < propNames.length; i++) {
            var propName = propNames[i];
            var track = tracks[propName];
            if (!track) {
                track = tracks[propName] = new Track(propName);
                var initialValue = void 0;
                var additiveTrack = this._getAdditiveTrack(propName);
                if (additiveTrack) {
                    var lastFinalKf = additiveTrack.keyframes[additiveTrack.keyframes.length - 1];
                    initialValue = lastFinalKf && lastFinalKf.value;
                    if (additiveTrack.isValueColor && initialValue) {
                        initialValue = rgba2String(initialValue);
                    }
                }
                else {
                    initialValue = this._target[propName];
                }
                if (initialValue == null) {
                    continue;
                }
                if (time !== 0) {
                    track.addKeyframe(0, cloneValue(initialValue));
                }
                this._trackKeys.push(propName);
            }
            track.addKeyframe(time, cloneValue(props[propName]));
        }
        this._maxTime = Math.max(this._maxTime, time);
        return this;
    };
    Animator.prototype.pause = function () {
        this._clip.pause();
        this._paused = true;
    };
    Animator.prototype.resume = function () {
        this._clip.resume();
        this._paused = false;
    };
    Animator.prototype.isPaused = function () {
        return !!this._paused;
    };
    Animator.prototype._doneCallback = function () {
        this._setTracksFinished();
        this._clip = null;
        var doneList = this._doneList;
        if (doneList) {
            var len = doneList.length;
            for (var i = 0; i < len; i++) {
                doneList[i].call(this);
            }
        }
    };
    Animator.prototype._abortedCallback = function () {
        this._setTracksFinished();
        var animation = this.animation;
        var abortedList = this._abortedList;
        if (animation) {
            animation.removeClip(this._clip);
        }
        this._clip = null;
        if (abortedList) {
            for (var i = 0; i < abortedList.length; i++) {
                abortedList[i].call(this);
            }
        }
    };
    Animator.prototype._setTracksFinished = function () {
        var tracks = this._tracks;
        var tracksKeys = this._trackKeys;
        for (var i = 0; i < tracksKeys.length; i++) {
            tracks[tracksKeys[i]].setFinished();
        }
    };
    Animator.prototype._getAdditiveTrack = function (trackName) {
        var additiveTrack;
        var additiveAnimators = this._additiveAnimators;
        if (additiveAnimators) {
            for (var i = 0; i < additiveAnimators.length; i++) {
                var track = additiveAnimators[i].getTrack(trackName);
                if (track) {
                    additiveTrack = track;
                }
            }
        }
        return additiveTrack;
    };
    Animator.prototype.start = function (easing, forceAnimate) {
        if (this._started > 0) {
            return;
        }
        this._started = 1;
        var self = this;
        var tracks = [];
        for (var i = 0; i < this._trackKeys.length; i++) {
            var propName = this._trackKeys[i];
            var track = this._tracks[propName];
            var additiveTrack = this._getAdditiveTrack(propName);
            var kfs = track.keyframes;
            track.prepare(additiveTrack);
            if (track.needsAnimate()) {
                tracks.push(track);
            }
            else if (!track.interpolable) {
                var lastKf = kfs[kfs.length - 1];
                if (lastKf) {
                    self._target[track.propName] = lastKf.value;
                }
            }
        }
        if (tracks.length || forceAnimate) {
            var clip = new animation_Clip({
                life: this._maxTime,
                loop: this._loop,
                delay: this._delay,
                onframe: function (percent) {
                    self._started = 2;
                    var additiveAnimators = self._additiveAnimators;
                    if (additiveAnimators) {
                        var stillHasAdditiveAnimator = false;
                        for (var i = 0; i < additiveAnimators.length; i++) {
                            if (additiveAnimators[i]._clip) {
                                stillHasAdditiveAnimator = true;
                                break;
                            }
                        }
                        if (!stillHasAdditiveAnimator) {
                            self._additiveAnimators = null;
                        }
                    }
                    for (var i = 0; i < tracks.length; i++) {
                        tracks[i].step(self._target, percent);
                    }
                    var onframeList = self._onframeList;
                    if (onframeList) {
                        for (var i = 0; i < onframeList.length; i++) {
                            onframeList[i](self._target, percent);
                        }
                    }
                },
                ondestroy: function () {
                    self._doneCallback();
                }
            });
            this._clip = clip;
            if (this.animation) {
                this.animation.addClip(clip);
            }
            if (easing && easing !== 'spline') {
                clip.easing = easing;
            }
        }
        else {
            this._doneCallback();
        }
        return this;
    };
    Animator.prototype.stop = function (forwardToLast) {
        if (!this._clip) {
            return;
        }
        var clip = this._clip;
        if (forwardToLast) {
            clip.onframe(1);
        }
        this._abortedCallback();
    };
    Animator.prototype.delay = function (time) {
        this._delay = time;
        return this;
    };
    Animator.prototype.during = function (cb) {
        if (cb) {
            if (!this._onframeList) {
                this._onframeList = [];
            }
            this._onframeList.push(cb);
        }
        return this;
    };
    Animator.prototype.done = function (cb) {
        if (cb) {
            if (!this._doneList) {
                this._doneList = [];
            }
            this._doneList.push(cb);
        }
        return this;
    };
    Animator.prototype.aborted = function (cb) {
        if (cb) {
            if (!this._abortedList) {
                this._abortedList = [];
            }
            this._abortedList.push(cb);
        }
        return this;
    };
    Animator.prototype.getClip = function () {
        return this._clip;
    };
    Animator.prototype.getTrack = function (propName) {
        return this._tracks[propName];
    };
    Animator.prototype.stopTracks = function (propNames, forwardToLast) {
        if (!propNames.length || !this._clip) {
            return true;
        }
        var tracks = this._tracks;
        var tracksKeys = this._trackKeys;
        for (var i = 0; i < propNames.length; i++) {
            var track = tracks[propNames[i]];
            if (track) {
                if (forwardToLast) {
                    track.step(this._target, 1);
                }
                else if (this._started === 1) {
                    track.step(this._target, 0);
                }
                track.setFinished();
            }
        }
        var allAborted = true;
        for (var i = 0; i < tracksKeys.length; i++) {
            if (!tracks[tracksKeys[i]].isFinished()) {
                allAborted = false;
                break;
            }
        }
        if (allAborted) {
            this._abortedCallback();
        }
        return allAborted;
    };
    Animator.prototype.saveFinalToTarget = function (target, trackKeys) {
        if (!target) {
            return;
        }
        trackKeys = trackKeys || this._trackKeys;
        for (var i = 0; i < trackKeys.length; i++) {
            var propName = trackKeys[i];
            var track = this._tracks[propName];
            if (!track || track.isFinished()) {
                continue;
            }
            var kfs = track.keyframes;
            var lastKf = kfs[kfs.length - 1];
            if (lastKf) {
                var val = cloneValue(lastKf.value);
                if (track.isValueColor) {
                    val = rgba2String(val);
                }
                target[propName] = val;
            }
        }
    };
    Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) {
        trackKeys = trackKeys || keys(finalProps);
        for (var i = 0; i < trackKeys.length; i++) {
            var propName = trackKeys[i];
            var track = this._tracks[propName];
            if (!track) {
                continue;
            }
            var kfs = track.keyframes;
            if (kfs.length > 1) {
                var lastKf = kfs.pop();
                track.addKeyframe(lastKf.time, finalProps[propName]);
                track.prepare(track.getAdditiveTrack());
            }
        }
    };
    return Animator;
}());
/* harmony default export */ const animation_Animator = (Animator);

;// CONCATENATED MODULE: ./src/util/animatableMixin.js


var animatableMixin = {

    _animators: null,

    getAnimators: function () {
        this._animators = this._animators || [];

        return this._animators;
    },

    animate: function (path, opts) {
        this._animators = this._animators || [];

        var el = this;

        var target;

        if (path) {
            var pathSplitted = path.split('.');
            var prop = el;
            for (var i = 0, l = pathSplitted.length; i < l; i++) {
                if (!prop) {
                    continue;
                }
                prop = prop[pathSplitted[i]];
            }
            if (prop) {
                target = prop;
            }
        }
        else {
            target = el;
        }
        if (target == null) {
            throw new Error('Target ' + path + ' not exists');
        }

        var animators = this._animators;

        var animator = new animation_Animator(target, opts);
        var self = this;
        animator.during(function () {
            if (self.__zr) {
                self.__zr.refresh();
            }
        }).done(function () {
            var idx = animators.indexOf(animator);
            if (idx >= 0) {
                animators.splice(idx, 1);
            }
        });
        animators.push(animator);

        if (this.__zr) {
            this.__zr.animation.addAnimator(animator);
        }

        return animator;
    },

    stopAnimation: function (forwardToLast) {
        this._animators = this._animators || [];

        var animators = this._animators;
        var len = animators.length;
        for (var i = 0; i < len; i++) {
            animators[i].stop(forwardToLast);
        }
        animators.length = 0;

        return this;
    },

    addAnimatorsToZr: function (zr) {
        if (this._animators) {
            for (var i = 0; i < this._animators.length; i++) {
                zr.animation.addAnimator(this._animators[i]);
            }
        }
    },

    removeAnimatorsFromZr: function (zr) {
        if (this._animators) {
            for (var i = 0; i < this._animators.length; i++) {
                zr.animation.removeAnimator(this._animators[i]);
            }
        }
    }
};

/* harmony default export */ const util_animatableMixin = (animatableMixin);
;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/util.glsl.js
/* harmony default export */ const util_glsl = ("\n@export clay.util.rand\nhighp float rand(vec2 uv) {\n const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n highp float dt = dot(uv.xy, vec2(a,b)), sn = mod(dt, 3.141592653589793);\n return fract(sin(sn) * c);\n}\n@end\n@export clay.util.calculate_attenuation\nuniform float attenuationFactor : 5.0;\nfloat lightAttenuation(float dist, float range)\n{\n float attenuation = 1.0;\n attenuation = dist*dist/(range*range+1.0);\n float att_s = attenuationFactor;\n attenuation = 1.0/(attenuation*att_s+1.0);\n att_s = 1.0/(att_s+1.0);\n attenuation = attenuation - att_s;\n attenuation /= 1.0 - att_s;\n return clamp(attenuation, 0.0, 1.0);\n}\n@end\n@export clay.util.edge_factor\n#ifdef SUPPORT_STANDARD_DERIVATIVES\nfloat edgeFactor(float width)\n{\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * width, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n#else\nfloat edgeFactor(float width)\n{\n return 1.0;\n}\n#endif\n@end\n@export clay.util.encode_float\nvec4 encodeFloat(const in float depth)\n{\n const vec4 bitShifts = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n vec4 res = fract(depth * bitShifts);\n res -= res.xxyz * bit_mask;\n return res;\n}\n@end\n@export clay.util.decode_float\nfloat decodeFloat(const in vec4 color)\n{\n const vec4 bitShifts = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n return dot(color, bitShifts);\n}\n@end\n@export clay.util.float\n@import clay.util.encode_float\n@import clay.util.decode_float\n@end\n@export clay.util.rgbm_decode\nvec3 RGBMDecode(vec4 rgbm, float range) {\n return range * rgbm.rgb * rgbm.a;\n}\n@end\n@export clay.util.rgbm_encode\nvec4 RGBMEncode(vec3 color, float range) {\n if (dot(color, color) == 0.0) {\n return vec4(0.0);\n }\n vec4 rgbm;\n color /= range;\n rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);\n rgbm.a = ceil(rgbm.a * 255.0) / 255.0;\n rgbm.rgb = color / rgbm.a;\n return rgbm;\n}\n@end\n@export clay.util.rgbm\n@import clay.util.rgbm_decode\n@import clay.util.rgbm_encode\nvec4 decodeHDR(vec4 color)\n{\n#if defined(RGBM_DECODE) || defined(RGBM)\n return vec4(RGBMDecode(color, 8.12), 1.0);\n#else\n return color;\n#endif\n}\nvec4 encodeHDR(vec4 color)\n{\n#if defined(RGBM_ENCODE) || defined(RGBM)\n return RGBMEncode(color.xyz, 8.12);\n#else\n return color;\n#endif\n}\n@end\n@export clay.util.srgb\nvec4 sRGBToLinear(in vec4 value) {\n return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.w);\n}\nvec4 linearTosRGB(in vec4 value) {\n return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.w);\n}\n@end\n@export clay.chunk.skinning_header\n#ifdef SKINNING\nattribute vec3 weight : WEIGHT;\nattribute vec4 joint : JOINT;\n#ifdef USE_SKIN_MATRICES_TEXTURE\nuniform sampler2D skinMatricesTexture : ignore;\nuniform float skinMatricesTextureSize: ignore;\nmat4 getSkinMatrix(sampler2D tex, float idx) {\n float j = idx * 4.0;\n float x = mod(j, skinMatricesTextureSize);\n float y = floor(j / skinMatricesTextureSize) + 0.5;\n vec2 scale = vec2(skinMatricesTextureSize);\n return mat4(\n texture2D(tex, vec2(x + 0.5, y) / scale),\n texture2D(tex, vec2(x + 1.5, y) / scale),\n texture2D(tex, vec2(x + 2.5, y) / scale),\n texture2D(tex, vec2(x + 3.5, y) / scale)\n );\n}\nmat4 getSkinMatrix(float idx) {\n return getSkinMatrix(skinMatricesTexture, idx);\n}\n#else\nuniform mat4 skinMatrix[JOINT_COUNT] : SKIN_MATRIX;\nmat4 getSkinMatrix(float idx) {\n return skinMatrix[int(idx)];\n}\n#endif\n#endif\n@end\n@export clay.chunk.skin_matrix\nmat4 skinMatrixWS = getSkinMatrix(joint.x) * weight.x;\nif (weight.y > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export clay.chunk.instancing_header\n#ifdef INSTANCING\nattribute vec4 instanceMat1;\nattribute vec4 instanceMat2;\nattribute vec4 instanceMat3;\n#endif\n@end\n@export clay.chunk.instancing_matrix\nmat4 instanceMat = mat4(\n vec4(instanceMat1.xyz, 0.0),\n vec4(instanceMat2.xyz, 0.0),\n vec4(instanceMat3.xyz, 0.0),\n vec4(instanceMat1.w, instanceMat2.w, instanceMat3.w, 1.0)\n);\n@end\n@export clay.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export clay.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end\n@export clay.util.ACES\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\n@end");

;// CONCATENATED MODULE: ./src/util/shader/common.glsl.js
/* harmony default export */ const common_glsl = ("\n@export ecgl.common.transformUniforms\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\n@end\n\n@export ecgl.common.attributes\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\n@end\n\n@export ecgl.common.uv.header\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nuniform vec2 detailUvRepeat : [1.0, 1.0];\nuniform vec2 detailUvOffset : [0.0, 0.0];\n\nvarying vec2 v_Texcoord;\nvarying vec2 v_DetailTexcoord;\n@end\n\n@export ecgl.common.uv.main\nv_Texcoord = texcoord * uvRepeat + uvOffset;\nv_DetailTexcoord = texcoord * detailUvRepeat + detailUvOffset;\n@end\n\n@export ecgl.common.uv.fragmentHeader\nvarying vec2 v_Texcoord;\nvarying vec2 v_DetailTexcoord;\n@end\n\n\n@export ecgl.common.albedo.main\n\n vec4 albedoTexel = vec4(1.0);\n#ifdef DIFFUSEMAP_ENABLED\n albedoTexel = texture2D(diffuseMap, v_Texcoord);\n #ifdef SRGB_DECODE\n albedoTexel = sRGBToLinear(albedoTexel);\n #endif\n#endif\n\n#ifdef DETAILMAP_ENABLED\n vec4 detailTexel = texture2D(detailMap, v_DetailTexcoord);\n #ifdef SRGB_DECODE\n detailTexel = sRGBToLinear(detailTexel);\n #endif\n albedoTexel.rgb = mix(albedoTexel.rgb, detailTexel.rgb, detailTexel.a);\n albedoTexel.a = detailTexel.a + (1.0 - detailTexel.a) * albedoTexel.a;\n#endif\n\n@end\n\n@export ecgl.common.wireframe.vertexHeader\n\n#ifdef WIREFRAME_QUAD\nattribute vec4 barycentric;\nvarying vec4 v_Barycentric;\n#elif defined(WIREFRAME_TRIANGLE)\nattribute vec3 barycentric;\nvarying vec3 v_Barycentric;\n#endif\n\n@end\n\n@export ecgl.common.wireframe.vertexMain\n\n#if defined(WIREFRAME_QUAD) || defined(WIREFRAME_TRIANGLE)\n v_Barycentric = barycentric;\n#endif\n\n@end\n\n\n@export ecgl.common.wireframe.fragmentHeader\n\nuniform float wireframeLineWidth : 1;\nuniform vec4 wireframeLineColor: [0, 0, 0, 0.5];\n\n#ifdef WIREFRAME_QUAD\nvarying vec4 v_Barycentric;\nfloat edgeFactor () {\n vec4 d = fwidth(v_Barycentric);\n vec4 a4 = smoothstep(vec4(0.0), d * wireframeLineWidth, v_Barycentric);\n return min(min(min(a4.x, a4.y), a4.z), a4.w);\n}\n#elif defined(WIREFRAME_TRIANGLE)\nvarying vec3 v_Barycentric;\nfloat edgeFactor () {\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * wireframeLineWidth, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n#endif\n\n@end\n\n\n@export ecgl.common.wireframe.fragmentMain\n\n#if defined(WIREFRAME_QUAD) || defined(WIREFRAME_TRIANGLE)\n if (wireframeLineWidth > 0.) {\n vec4 lineColor = wireframeLineColor;\n#ifdef SRGB_DECODE\n lineColor = sRGBToLinear(lineColor);\n#endif\n\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor()) * lineColor.a);\n }\n#endif\n@end\n\n\n\n\n@export ecgl.common.bumpMap.header\n\n#ifdef BUMPMAP_ENABLED\nuniform sampler2D bumpMap;\nuniform float bumpScale : 1.0;\n\n\nvec3 bumpNormal(vec3 surfPos, vec3 surfNormal, vec3 baseNormal)\n{\n vec2 dSTdx = dFdx(v_Texcoord);\n vec2 dSTdy = dFdy(v_Texcoord);\n\n float Hll = bumpScale * texture2D(bumpMap, v_Texcoord).x;\n float dHx = bumpScale * texture2D(bumpMap, v_Texcoord + dSTdx).x - Hll;\n float dHy = bumpScale * texture2D(bumpMap, v_Texcoord + dSTdy).x - Hll;\n\n vec3 vSigmaX = dFdx(surfPos);\n vec3 vSigmaY = dFdy(surfPos);\n vec3 vN = surfNormal;\n\n vec3 R1 = cross(vSigmaY, vN);\n vec3 R2 = cross(vN, vSigmaX);\n\n float fDet = dot(vSigmaX, R1);\n\n vec3 vGrad = sign(fDet) * (dHx * R1 + dHy * R2);\n return normalize(abs(fDet) * baseNormal - vGrad);\n\n}\n#endif\n\n@end\n\n@export ecgl.common.normalMap.vertexHeader\n\n#ifdef NORMALMAP_ENABLED\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n\n@end\n\n@export ecgl.common.normalMap.vertexMain\n\n#ifdef NORMALMAP_ENABLED\n if (dot(tangent, tangent) > 0.0) {\n v_Tangent = normalize((worldInverseTranspose * vec4(tangent.xyz, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n#endif\n\n@end\n\n\n@export ecgl.common.normalMap.fragmentHeader\n\n#ifdef NORMALMAP_ENABLED\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n\n@end\n\n@export ecgl.common.normalMap.fragmentMain\n#ifdef NORMALMAP_ENABLED\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_DetailTexcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n#endif\n@end\n\n\n\n@export ecgl.common.vertexAnimation.header\n\n#ifdef VERTEX_ANIMATION\nattribute vec3 prevPosition;\nattribute vec3 prevNormal;\nuniform float percent;\n#endif\n\n@end\n\n@export ecgl.common.vertexAnimation.main\n\n#ifdef VERTEX_ANIMATION\n vec3 pos = mix(prevPosition, position, percent);\n vec3 norm = mix(prevNormal, normal, percent);\n#else\n vec3 pos = position;\n vec3 norm = normal;\n#endif\n\n@end\n\n\n@export ecgl.common.ssaoMap.header\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n@end\n\n@export ecgl.common.ssaoMap.main\n float ao = 1.0;\n#ifdef SSAOMAP_ENABLED\n ao = texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n@end\n\n\n\n\n@export ecgl.common.diffuseLayer.header\n\n#if (LAYER_DIFFUSEMAP_COUNT > 0)\nuniform float layerDiffuseIntensity[LAYER_DIFFUSEMAP_COUNT];\nuniform sampler2D layerDiffuseMap[LAYER_DIFFUSEMAP_COUNT];\n#endif\n\n@end\n\n@export ecgl.common.emissiveLayer.header\n\n#if (LAYER_EMISSIVEMAP_COUNT > 0)\nuniform float layerEmissionIntensity[LAYER_EMISSIVEMAP_COUNT];\nuniform sampler2D layerEmissiveMap[LAYER_EMISSIVEMAP_COUNT];\n#endif\n\n@end\n\n@export ecgl.common.layers.header\n@import ecgl.common.diffuseLayer.header\n@import ecgl.common.emissiveLayer.header\n@end\n\n@export ecgl.common.diffuseLayer.main\n\n#if (LAYER_DIFFUSEMAP_COUNT > 0)\n for (int _idx_ = 0; _idx_ < LAYER_DIFFUSEMAP_COUNT; _idx_++) {{\n float intensity = layerDiffuseIntensity[_idx_];\n vec4 texel2 = texture2D(layerDiffuseMap[_idx_], v_Texcoord);\n #ifdef SRGB_DECODE\n texel2 = sRGBToLinear(texel2);\n #endif\n albedoTexel.rgb = mix(albedoTexel.rgb, texel2.rgb * intensity, texel2.a);\n albedoTexel.a = texel2.a + (1.0 - texel2.a) * albedoTexel.a;\n }}\n#endif\n\n@end\n\n@export ecgl.common.emissiveLayer.main\n\n#if (LAYER_EMISSIVEMAP_COUNT > 0)\n for (int _idx_ = 0; _idx_ < LAYER_EMISSIVEMAP_COUNT; _idx_++)\n {{\n vec4 texel2 = texture2D(layerEmissiveMap[_idx_], v_Texcoord) * layerEmissionIntensity[_idx_];\n #ifdef SRGB_DECODE\n texel2 = sRGBToLinear(texel2);\n #endif\n float intensity = layerEmissionIntensity[_idx_];\n gl_FragColor.rgb += texel2.rgb * texel2.a * intensity;\n }}\n#endif\n\n@end\n");

;// CONCATENATED MODULE: ./src/util/shader/color.glsl.js
/* harmony default export */ const color_glsl = ("@export ecgl.color.vertex\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\n@import ecgl.common.uv.header\n\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position: POSITION;\n\n@import ecgl.common.wireframe.vertexHeader\n\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n\n#ifdef VERTEX_ANIMATION\nattribute vec3 prevPosition;\nuniform float percent : 1.0;\n#endif\n\n#ifdef ATMOSPHERE_ENABLED\nattribute vec3 normal: NORMAL;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nvarying vec3 v_Normal;\n#endif\n\nvoid main()\n{\n#ifdef VERTEX_ANIMATION\n vec3 pos = mix(prevPosition, position, percent);\n#else\n vec3 pos = position;\n#endif\n\n gl_Position = worldViewProjection * vec4(pos, 1.0);\n\n @import ecgl.common.uv.main\n\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n\n#ifdef ATMOSPHERE_ENABLED\n v_Normal = normalize((worldInverseTranspose * vec4(normal, 0.0)).xyz);\n#endif\n\n @import ecgl.common.wireframe.vertexMain\n\n}\n\n@end\n\n@export ecgl.color.fragment\n\n#define LAYER_DIFFUSEMAP_COUNT 0\n#define LAYER_EMISSIVEMAP_COUNT 0\n\nuniform sampler2D diffuseMap;\nuniform sampler2D detailMap;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\n#ifdef ATMOSPHERE_ENABLED\nuniform mat4 viewTranspose: VIEWTRANSPOSE;\nuniform vec3 glowColor;\nuniform float glowPower;\nvarying vec3 v_Normal;\n#endif\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n\n@import ecgl.common.layers.header\n\n@import ecgl.common.uv.fragmentHeader\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.util.srgb\n\nvoid main()\n{\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(color);\n#else\n gl_FragColor = color;\n#endif\n\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n\n @import ecgl.common.albedo.main\n\n @import ecgl.common.diffuseLayer.main\n\n gl_FragColor *= albedoTexel;\n\n#ifdef ATMOSPHERE_ENABLED\n float atmoIntensity = pow(1.0 - dot(v_Normal, (viewTranspose * vec4(0.0, 0.0, 1.0, 0.0)).xyz), glowPower);\n gl_FragColor.rgb += glowColor * atmoIntensity;\n#endif\n\n @import ecgl.common.emissiveLayer.main\n\n @import ecgl.common.wireframe.fragmentMain\n\n}\n@end");

;// CONCATENATED MODULE: ./src/util/shader/lambert.glsl.js
/* harmony default export */ const lambert_glsl = ("/**\n * http: */\n\n@export ecgl.lambert.vertex\n\n@import ecgl.common.transformUniforms\n\n@import ecgl.common.uv.header\n\n\n@import ecgl.common.attributes\n\n@import ecgl.common.wireframe.vertexHeader\n\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n\n\n@import ecgl.common.vertexAnimation.header\n\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nvoid main()\n{\n @import ecgl.common.uv.main\n\n @import ecgl.common.vertexAnimation.main\n\n\n gl_Position = worldViewProjection * vec4(pos, 1.0);\n\n v_Normal = normalize((worldInverseTranspose * vec4(norm, 0.0)).xyz);\n v_WorldPosition = (world * vec4(pos, 1.0)).xyz;\n\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n\n @import ecgl.common.wireframe.vertexMain\n}\n\n@end\n\n\n@export ecgl.lambert.fragment\n\n#define LAYER_DIFFUSEMAP_COUNT 0\n#define LAYER_EMISSIVEMAP_COUNT 0\n\n#define NORMAL_UP_AXIS 1\n#define NORMAL_FRONT_AXIS 2\n\n@import ecgl.common.uv.fragmentHeader\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform sampler2D diffuseMap;\nuniform sampler2D detailMap;\n\n@import ecgl.common.layers.header\n\nuniform float emissionIntensity: 1.0;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nuniform mat4 viewInverse : VIEWINVERSE;\n\n#ifdef ATMOSPHERE_ENABLED\nuniform mat4 viewTranspose: VIEWTRANSPOSE;\nuniform vec3 glowColor;\nuniform float glowPower;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n\n\n@import ecgl.common.ssaoMap.header\n\n@import ecgl.common.bumpMap.header\n\n@import clay.util.srgb\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(color);\n#else\n gl_FragColor = color;\n#endif\n\n#ifdef VERTEX_COLOR\n #ifdef SRGB_DECODE\n gl_FragColor *= sRGBToLinear(v_Color);\n #else\n gl_FragColor *= v_Color;\n #endif\n#endif\n\n @import ecgl.common.albedo.main\n\n @import ecgl.common.diffuseLayer.main\n\n gl_FragColor *= albedoTexel;\n\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n\n float ambientFactor = 1.0;\n\n#ifdef BUMPMAP_ENABLED\n N = bumpNormal(v_WorldPosition, v_Normal, N);\n ambientFactor = dot(v_Normal, N);\n#endif\n\n vec3 N2 = vec3(N.x, N[NORMAL_UP_AXIS], N[NORMAL_FRONT_AXIS]);\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n @import ecgl.common.ssaoMap.main\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int i = 0; i < AMBIENT_LIGHT_COUNT; i++)\n {\n diffuseColor += ambientLightColor[i] * ambientFactor * ao;\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, N2) * ambientSHLightColor[_idx_] * ao;\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n float ndl = dot(N, normalize(lightDirection)) * shadowContrib;\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0);\n }\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n#ifdef ATMOSPHERE_ENABLED\n float atmoIntensity = pow(1.0 - dot(v_Normal, (viewTranspose * vec4(0.0, 0.0, 1.0, 0.0)).xyz), glowPower);\n gl_FragColor.rgb += glowColor * atmoIntensity;\n#endif\n\n @import ecgl.common.emissiveLayer.main\n\n @import ecgl.common.wireframe.fragmentMain\n}\n\n@end");

;// CONCATENATED MODULE: ./src/util/shader/realistic.glsl.js
/* harmony default export */ const realistic_glsl = ("@export ecgl.realistic.vertex\n\n@import ecgl.common.transformUniforms\n\n@import ecgl.common.uv.header\n\n@import ecgl.common.attributes\n\n\n@import ecgl.common.wireframe.vertexHeader\n\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n\n#ifdef NORMALMAP_ENABLED\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n\n@import ecgl.common.vertexAnimation.header\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nvoid main()\n{\n\n @import ecgl.common.uv.main\n\n @import ecgl.common.vertexAnimation.main\n\n gl_Position = worldViewProjection * vec4(pos, 1.0);\n\n v_Normal = normalize((worldInverseTranspose * vec4(norm, 0.0)).xyz);\n v_WorldPosition = (world * vec4(pos, 1.0)).xyz;\n\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n\n#ifdef NORMALMAP_ENABLED\n v_Tangent = normalize((worldInverseTranspose * vec4(tangent.xyz, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n#endif\n\n @import ecgl.common.wireframe.vertexMain\n\n}\n\n@end\n\n\n\n@export ecgl.realistic.fragment\n\n#define LAYER_DIFFUSEMAP_COUNT 0\n#define LAYER_EMISSIVEMAP_COUNT 0\n#define PI 3.14159265358979\n#define ROUGHNESS_CHANEL 0\n#define METALNESS_CHANEL 1\n\n#define NORMAL_UP_AXIS 1\n#define NORMAL_FRONT_AXIS 2\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n\n@import ecgl.common.uv.fragmentHeader\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform sampler2D diffuseMap;\n\nuniform sampler2D detailMap;\nuniform sampler2D metalnessMap;\nuniform sampler2D roughnessMap;\n\n@import ecgl.common.layers.header\n\nuniform float emissionIntensity: 1.0;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nuniform float metalness : 0.0;\nuniform float roughness : 0.5;\n\nuniform mat4 viewInverse : VIEWINVERSE;\n\n#ifdef ATMOSPHERE_ENABLED\nuniform mat4 viewTranspose: VIEWTRANSPOSE;\nuniform vec3 glowColor;\nuniform float glowPower;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n@import clay.header.ambient_cubemap_light\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import ecgl.common.normalMap.fragmentHeader\n\n@import ecgl.common.ssaoMap.header\n\n@import ecgl.common.bumpMap.header\n\n@import clay.util.srgb\n\n@import clay.util.rgbm\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.plugin.compute_shadow_map\n\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\n\nfloat D_Phong(float g, float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\n\nvoid main()\n{\n vec4 albedoColor = color;\n\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n#ifdef VERTEX_COLOR\n #ifdef SRGB_DECODE\n albedoColor *= sRGBToLinear(v_Color);\n #else\n albedoColor *= v_Color;\n #endif\n#endif\n\n @import ecgl.common.albedo.main\n\n @import ecgl.common.diffuseLayer.main\n\n albedoColor *= albedoTexel;\n\n float m = metalness;\n\n#ifdef METALNESSMAP_ENABLED\n float m2 = texture2D(metalnessMap, v_DetailTexcoord)[METALNESS_CHANEL];\n m = clamp(m2 + (m - 0.5) * 2.0, 0.0, 1.0);\n#endif\n\n vec3 baseColor = albedoColor.rgb;\n albedoColor.rgb = baseColor * (1.0 - m);\n vec3 specFactor = mix(vec3(0.04), baseColor, m);\n\n float g = 1.0 - roughness;\n\n#ifdef ROUGHNESSMAP_ENABLED\n float g2 = 1.0 - texture2D(roughnessMap, v_DetailTexcoord)[ROUGHNESS_CHANEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n#endif\n\n vec3 N = v_Normal;\n\n#ifdef DOUBLE_SIDED\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n\n float ambientFactor = 1.0;\n\n#ifdef BUMPMAP_ENABLED\n N = bumpNormal(v_WorldPosition, v_Normal, N);\n ambientFactor = dot(v_Normal, N);\n#endif\n\n@import ecgl.common.normalMap.fragmentMain\n\n vec3 N2 = vec3(N.x, N[NORMAL_UP_AXIS], N[NORMAL_FRONT_AXIS]);\n\n vec3 diffuseTerm = vec3(0.0);\n vec3 specularTerm = vec3(0.0);\n\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, specFactor);\n\n @import ecgl.common.ssaoMap.main\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_] * ambientFactor * ao;\n }}\n#endif\n\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N2) * ambientSHLightColor[_idx_] * ao;\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -directionalLightDirection[_idx_];\n vec3 lc = directionalLightColor[_idx_];\n\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, normalize(L)), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n\n vec3 li = lc * ndl * shadowContrib;\n\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n\n\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n L = vec3(L.x, L[NORMAL_UP_AXIS], L[NORMAL_FRONT_AXIS]);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = specFactor * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 8.12);\n specularTerm += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2 * ao;\n }}\n#endif\n\n gl_FragColor.rgb = albedoColor.rgb * diffuseTerm + specularTerm;\n gl_FragColor.a = albedoColor.a;\n\n#ifdef ATMOSPHERE_ENABLED\n float atmoIntensity = pow(1.0 - dot(v_Normal, (viewTranspose * vec4(0.0, 0.0, 1.0, 0.0)).xyz), glowPower);\n gl_FragColor.rgb += glowColor * atmoIntensity;\n#endif\n\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n\n @import ecgl.common.emissiveLayer.main\n\n @import ecgl.common.wireframe.fragmentMain\n}\n\n@end");

;// CONCATENATED MODULE: ./src/util/shader/hatching.glsl.js
/* harmony default export */ const hatching_glsl = ("@export ecgl.hatching.vertex\n\n@import ecgl.realistic.vertex\n\n@end\n\n\n@export ecgl.hatching.fragment\n\n#define NORMAL_UP_AXIS 1\n#define NORMAL_FRONT_AXIS 2\n\n@import ecgl.common.uv.fragmentHeader\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [0.0, 0.0, 0.0, 1.0];\nuniform vec4 paperColor : [1.0, 1.0, 1.0, 1.0];\n\nuniform mat4 viewInverse : VIEWINVERSE;\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n\n\n@import ecgl.common.ssaoMap.header\n\n@import ecgl.common.bumpMap.header\n\n@import clay.util.srgb\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.plugin.compute_shadow_map\n\nuniform sampler2D hatch1;\nuniform sampler2D hatch2;\nuniform sampler2D hatch3;\nuniform sampler2D hatch4;\nuniform sampler2D hatch5;\nuniform sampler2D hatch6;\n\nfloat shade(in float tone) {\n vec4 c = vec4(1. ,1., 1., 1.);\n float step = 1. / 6.;\n vec2 uv = v_DetailTexcoord;\n if (tone <= step / 2.0) {\n c = mix(vec4(0.), texture2D(hatch6, uv), 12. * tone);\n }\n else if (tone <= step) {\n c = mix(texture2D(hatch6, uv), texture2D(hatch5, uv), 6. * tone);\n }\n if(tone > step && tone <= 2. * step){\n c = mix(texture2D(hatch5, uv), texture2D(hatch4, uv) , 6. * (tone - step));\n }\n if(tone > 2. * step && tone <= 3. * step){\n c = mix(texture2D(hatch4, uv), texture2D(hatch3, uv), 6. * (tone - 2. * step));\n }\n if(tone > 3. * step && tone <= 4. * step){\n c = mix(texture2D(hatch3, uv), texture2D(hatch2, uv), 6. * (tone - 3. * step));\n }\n if(tone > 4. * step && tone <= 5. * step){\n c = mix(texture2D(hatch2, uv), texture2D(hatch1, uv), 6. * (tone - 4. * step));\n }\n if(tone > 5. * step){\n c = mix(texture2D(hatch1, uv), vec4(1.), 6. * (tone - 5. * step));\n }\n\n return c.r;\n}\n\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n\nvoid main()\n{\n#ifdef SRGB_DECODE\n vec4 inkColor = sRGBToLinear(color);\n#else\n vec4 inkColor = color;\n#endif\n\n#ifdef VERTEX_COLOR\n #ifdef SRGB_DECODE\n inkColor *= sRGBToLinear(v_Color);\n #else\n inkColor *= v_Color;\n #endif\n#endif\n\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n\n float tone = 0.0;\n\n float ambientFactor = 1.0;\n\n#ifdef BUMPMAP_ENABLED\n N = bumpNormal(v_WorldPosition, v_Normal, N);\n ambientFactor = dot(v_Normal, N);\n#endif\n\n vec3 N2 = vec3(N.x, N[NORMAL_UP_AXIS], N[NORMAL_FRONT_AXIS]);\n\n @import ecgl.common.ssaoMap.main\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int i = 0; i < AMBIENT_LIGHT_COUNT; i++)\n {\n tone += dot(ambientLightColor[i], w) * ambientFactor * ao;\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n tone += dot(calcAmbientSHLight(_idx_, N2) * ambientSHLightColor[_idx_], w) * ao;\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n float lightTone = dot(directionalLightColor[i], w);\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n float ndl = dot(N, normalize(lightDirection)) * shadowContrib;\n\n tone += lightTone * clamp(ndl, 0.0, 1.0);\n }\n#endif\n\n gl_FragColor = mix(inkColor, paperColor, shade(clamp(tone, 0.0, 1.0)));\n }\n@end\n");

;// CONCATENATED MODULE: ./src/util/shader/shadow.glsl.js
/* harmony default export */ const shadow_glsl = ("@export ecgl.sm.depth.vertex\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n\n#ifdef VERTEX_ANIMATION\nattribute vec3 prevPosition;\nuniform float percent : 1.0;\n#endif\n\nvarying vec4 v_ViewPosition;\nvarying vec2 v_Texcoord;\n\nvoid main(){\n\n#ifdef VERTEX_ANIMATION\n vec3 pos = mix(prevPosition, position, percent);\n#else\n vec3 pos = position;\n#endif\n\n v_ViewPosition = worldViewProjection * vec4(pos, 1.0);\n gl_Position = v_ViewPosition;\n\n v_Texcoord = texcoord;\n\n}\n@end\n\n\n\n@export ecgl.sm.depth.fragment\n\n@import clay.sm.depth.fragment\n\n@end");

;// CONCATENATED MODULE: ./src/util/graphicGL.js






























// Math

















// Some common shaders










Object.assign(src_Node.prototype, util_animatableMixin);

src_Shader.import(util_glsl);
src_Shader.import(prez_glsl);
src_Shader.import(common_glsl);
src_Shader.import(color_glsl);
src_Shader.import(lambert_glsl);
src_Shader.import(realistic_glsl);
src_Shader.import(hatching_glsl);
src_Shader.import(shadow_glsl);

function isValueNone(value) {
    return !value || value === 'none';
}

function isValueImage(value) {
    return value instanceof HTMLCanvasElement
        || value instanceof HTMLImageElement
        || value instanceof Image;
}

function isECharts(value) {
    return value.getZr && value.setOption;
}

// Overwrite addToScene and removeFromScene
var oldAddToScene = src_Scene.prototype.addToScene;
var oldRemoveFromScene = src_Scene.prototype.removeFromScene;

src_Scene.prototype.addToScene = function (node) {
    oldAddToScene.call(this, node);

    if (this.__zr) {
        var zr = this.__zr;
        node.traverse(function (child) {
            child.__zr = zr;
            if (child.addAnimatorsToZr) {
                child.addAnimatorsToZr(zr);
            }
        });
    }
};

src_Scene.prototype.removeFromScene = function (node) {
    oldRemoveFromScene.call(this, node);

    node.traverse(function (child) {
        var zr = child.__zr;
        child.__zr = null;
        if (zr && child.removeAnimatorsFromZr) {
            child.removeAnimatorsFromZr(zr);
        }
    });
};

/**
 * @param {string} textureName
 * @param {string|HTMLImageElement|HTMLCanvasElement} imgValue
 * @param {module:echarts/ExtensionAPI} api
 * @param {Object} [textureOpts]
 */
src_Material.prototype.setTextureImage = function (textureName, imgValue, api, textureOpts) {
    if (!this.shader) {
        return;
    }

    var zr = api.getZr();
    var material = this;
    var texture;
    material.autoUpdateTextureStatus = false;
    // disableTexture first
    material.disableTexture(textureName);
    if (!isValueNone(imgValue)) {
        texture = graphicGL.loadTexture(imgValue, api, textureOpts, function (texture) {
            material.enableTexture(textureName);
            zr && zr.refresh();
        });
        // Set texture immediately for other code to verify if have this texture.
        material.set(textureName, texture);
    }

    return texture;
};

var graphicGL = {};

graphicGL.Renderer = src_Renderer;

graphicGL.Node = src_Node;

graphicGL.Mesh = src_Mesh;

graphicGL.Shader = src_Shader;

graphicGL.Material = src_Material;

graphicGL.Texture = src_Texture;

graphicGL.Texture2D = src_Texture2D;

// Geometries
graphicGL.Geometry = src_Geometry;
graphicGL.SphereGeometry = geometry_Sphere;
graphicGL.PlaneGeometry = geometry_Plane;
graphicGL.CubeGeometry = geometry_Cube;

// Lights
graphicGL.AmbientLight = Ambient;
graphicGL.DirectionalLight = Directional;
graphicGL.PointLight = Point;
graphicGL.SpotLight = Spot;

// Cameras
graphicGL.PerspectiveCamera = camera_Perspective;
graphicGL.OrthographicCamera = camera_Orthographic;

// Math
graphicGL.Vector2 = math_Vector2;
graphicGL.Vector3 = math_Vector3;
graphicGL.Vector4 = math_Vector4;

graphicGL.Quaternion = math_Quaternion;

graphicGL.Matrix2 = math_Matrix2;
graphicGL.Matrix2d = math_Matrix2d;
graphicGL.Matrix3 = math_Matrix3;
graphicGL.Matrix4 = math_Matrix4;

graphicGL.Plane = math_Plane;
graphicGL.Ray = math_Ray;
graphicGL.BoundingBox = math_BoundingBox;
graphicGL.Frustum = math_Frustum;

// Texture utilities
var blankImage = null;

function getBlankImage() {
    if (blankImage !== null) {
        return blankImage;
    }
    blankImage = util_texture.createBlank('rgba(255,255,255,0)').image;
    return blankImage;
}


function graphicGL_nearestPowerOfTwo(val) {
    return Math.pow(2, Math.round(Math.log(val) / Math.LN2));
}
function graphicGL_convertTextureToPowerOfTwo(texture) {
    if ((texture.wrapS === src_Texture.REPEAT || texture.wrapT === src_Texture.REPEAT) && texture.image) {
        // var canvas = document.createElement('canvas');
        var width = graphicGL_nearestPowerOfTwo(texture.width);
        var height = graphicGL_nearestPowerOfTwo(texture.height);
        if (width !== texture.width || height !== texture.height) {
            var canvas = document.createElement('canvas');
            canvas.width = width;
            canvas.height = height;
            var ctx = canvas.getContext('2d');
            ctx.drawImage(texture.image, 0, 0, width, height);
            texture.image = canvas;
        }
    }
}
/**
 * @param {string|HTMLImageElement|HTMLCanvasElement} imgValue
 * @param {module:echarts/ExtensionAPI} api
 * @param {Object} [textureOpts]
 * @param {Function} cb
 */
// TODO Promise, test
graphicGL.loadTexture = function (imgValue, api, textureOpts, cb) {
    if (typeof textureOpts === 'function') {
        cb = textureOpts;
        textureOpts = {};
    }
    textureOpts = textureOpts || {};

    var keys = Object.keys(textureOpts).sort();
    var prefix = '';
    for (var i = 0; i < keys.length; i++) {
        prefix += keys[i] + '_' + textureOpts[keys[i]] + '_';
    }

    var textureCache = api.__textureCache = api.__textureCache || new lib_core_LRU(20);

    if (isECharts(imgValue)) {
        var id = imgValue.__textureid__;
        var textureObj = textureCache.get(prefix + id);
        if (!textureObj) {
            var surface = new util_EChartsSurface(imgValue);
            surface.onupdate = function () {
                api.getZr().refresh();
            };
            textureObj = {
                texture: surface.getTexture()
            };
            for (var i = 0; i < keys.length; i++) {
                textureObj.texture[keys[i]] = textureOpts[keys[i]];
            }
            id = imgValue.__textureid__ || '__ecgl_ec__' + textureObj.texture.__uid__;
            imgValue.__textureid__ = id;
            textureCache.put(prefix + id, textureObj);
            cb && cb(textureObj.texture);
        }
        else {
            textureObj.texture.surface.setECharts(imgValue);

            cb && cb(textureObj.texture);
        }
        return textureObj.texture;
    }
    else if (isValueImage(imgValue)) {
        var id = imgValue.__textureid__;
        var textureObj = textureCache.get(prefix + id);
        if (!textureObj) {
            textureObj = {
                texture: new graphicGL.Texture2D({
                    image: imgValue
                })
            };
            for (var i = 0; i < keys.length; i++) {
                textureObj.texture[keys[i]] = textureOpts[keys[i]];
            }
            id = imgValue.__textureid__ || '__ecgl_image__' + textureObj.texture.__uid__;
            imgValue.__textureid__ = id;
            textureCache.put(prefix + id, textureObj);

            graphicGL_convertTextureToPowerOfTwo(textureObj.texture);
            // TODO Next tick?
            cb && cb(textureObj.texture);
        }
        return textureObj.texture;
    }
    else {
        var textureObj = textureCache.get(prefix + imgValue);
        if (textureObj) {
            if (textureObj.callbacks) {
                // Add to pending callbacks
                textureObj.callbacks.push(cb);
            }
            else {
                // TODO Next tick?
                cb && cb(textureObj.texture);
            }
        }
        else {
            // Maybe base64
            if (imgValue.match(/.hdr$|^data:application\/octet-stream/)) {
                textureObj = {
                    callbacks: [cb]
                };
                var texture = util_texture.loadTexture(imgValue, {
                    exposure: textureOpts.exposure,
                    fileType: 'hdr'
                }, function () {
                    texture.dirty();
                    textureObj.callbacks.forEach(function (cb) {
                        cb && cb(texture);
                    });
                    textureObj.callbacks = null;
                });
                textureObj.texture = texture;
                textureCache.put(prefix + imgValue, textureObj);
            }
            else {
                var texture = new graphicGL.Texture2D({
                    image: new Image()
                });
                for (var i = 0; i < keys.length; i++) {
                    texture[keys[i]] = textureOpts[keys[i]];
                }

                textureObj = {
                    texture: texture,
                    callbacks: [cb]
                };
                var originalImage = texture.image;
                originalImage.onload = function () {
                    texture.image = originalImage;
                    graphicGL_convertTextureToPowerOfTwo(texture);

                    texture.dirty();
                    textureObj.callbacks.forEach(function (cb) {
                        cb && cb(texture);
                    });
                    textureObj.callbacks = null;
                };
                originalImage.crossOrigin = 'Anonymous';
                originalImage.src = imgValue;
                // Use blank image as place holder.
                texture.image = getBlankImage();

                textureCache.put(prefix + imgValue, textureObj);
            }
        }

        return textureObj.texture;
    }
};

/**
 * Create ambientCubemap and ambientSH light. respectively to have specular and diffuse light
 * @return {Object} { specular, diffuse }
 */
graphicGL.createAmbientCubemap = function (opt, renderer, api, cb) {
    opt = opt || {};
    var textureUrl = opt.texture;
    var exposure = util_retrieve.firstNotNull(opt.exposure, 1.0);

    var ambientCubemap = new AmbientCubemap({
        intensity: util_retrieve.firstNotNull(opt.specularIntensity, 1.0)
    });
    var ambientSH = new AmbientSH({
        intensity: util_retrieve.firstNotNull(opt.diffuseIntensity, 1.0),
        coefficients: [0.844, 0.712, 0.691, -0.037, 0.083, 0.167, 0.343, 0.288, 0.299, -0.041, -0.021, -0.009, -0.003, -0.041, -0.064, -0.011, -0.007, -0.004, -0.031, 0.034, 0.081, -0.060, -0.049, -0.060, 0.046, 0.056, 0.050]
    });


    ambientCubemap.cubemap = graphicGL.loadTexture(textureUrl, api, {
        exposure: exposure
    }, function () {
        // TODO Performance when multiple view
        ambientCubemap.cubemap.flipY = false;
        if (true) {
            var time = Date.now();
        }
        ambientCubemap.prefilter(renderer, 32);
        if (true) {
            var dTime = Date.now() - time;
            console.log('Prefilter environment map: ' + dTime + 'ms');
        }
        ambientSH.coefficients = util_sh.projectEnvironmentMap(renderer, ambientCubemap.cubemap, {
            lod: 1
        });

        cb && cb();

        // TODO Refresh ?
    });

    return {
        specular: ambientCubemap,
        diffuse: ambientSH
    };
};

/**
 * Create a blank texture for placeholder
 */
graphicGL.createBlankTexture = util_texture.createBlank;

/**
 * If value is image
 * @param {*}
 * @return {boolean}
 */
graphicGL.isImage = isValueImage;

graphicGL.additiveBlend = function (gl) {
    gl.blendEquation(gl.FUNC_ADD);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
};

/**
 * @param {string|Array.<number>} colorStr
 * @param {Array.<number>} [rgba]
 * @return {Array.<number>} rgba
 */
graphicGL.parseColor = function (colorStr, rgba) {
    if (colorStr instanceof Array) {
        if (!rgba) {
            rgba = [];
        }
        // Color has been parsed.
        rgba[0] = colorStr[0];
        rgba[1] = colorStr[1];
        rgba[2] = colorStr[2];
        if (colorStr.length > 3) {
            rgba[3] = colorStr[3];
        }
        else {
            rgba[3] = 1;
        }
        return rgba;
    }

    rgba = external_echarts_.color.parse(colorStr || '#000', rgba) || [0, 0, 0, 0];
    rgba[0] /= 255;
    rgba[1] /= 255;
    rgba[2] /= 255;
    return rgba;
};

/**
 * Convert alpha beta rotation to direction.
 * @param {number} alpha
 * @param {number} beta
 * @return {Array.<number>}
 */
graphicGL.directionFromAlphaBeta = function (alpha, beta) {
    var theta = alpha / 180 * Math.PI + Math.PI / 2;
    var phi = -beta / 180 * Math.PI + Math.PI / 2;

    var dir = [];
    var r = Math.sin(theta);
    dir[0] = r * Math.cos(phi);
    dir[1] = -Math.cos(theta);
    dir[2] = r * Math.sin(phi);

    return dir;
};
/**
 * Get shadow resolution from shadowQuality configuration
 */
graphicGL.getShadowResolution = function (shadowQuality) {
    var shadowResolution = 1024;
    switch (shadowQuality) {
        case 'low':
            shadowResolution = 512;
            break;
        case 'medium':
            break;
        case 'high':
            shadowResolution = 2048;
            break;
        case 'ultra':
            shadowResolution = 4096;
            break;
    }
    return shadowResolution;
};

/**
 * Shading utilities
 */
graphicGL.COMMON_SHADERS = ['lambert', 'color', 'realistic', 'hatching', 'shadow'];

/**
 * Create shader including vertex and fragment
 * @param {string} prefix.
 */
graphicGL.createShader = function (prefix) {
    if (prefix === 'ecgl.shadow') {
        prefix = 'ecgl.displayShadow';
    }
    var vertexShaderStr = src_Shader.source(prefix + '.vertex');
    var fragmentShaderStr = src_Shader.source(prefix + '.fragment');
    if (!vertexShaderStr) {
        console.error('Vertex shader of \'%s\' not exits', prefix);
    }
    if (!fragmentShaderStr) {
        console.error('Fragment shader of \'%s\' not exits', prefix);
    }
    var shader = new src_Shader(vertexShaderStr, fragmentShaderStr);
    shader.name = prefix;
    return shader;
};

graphicGL.createMaterial = function (prefix, defines) {
    if (!(defines instanceof Array)) {
        defines = [defines];
    }
    var shader = graphicGL.createShader(prefix);
    var material = new src_Material({
        shader: shader
    });
    defines.forEach(function (defineName) {
        if (typeof defineName === 'string') {
            material.define(defineName);
        }
    });
    return material;
};
/**
 * Set material from model.
 * @param {clay.Material} material
 * @param {module:echarts/model/Model} model
 * @param {module:echarts/ExtensionAPI} api
 */
graphicGL.setMaterialFromModel = function (shading, material, model, api) {
    material.autoUpdateTextureStatus = false;

    var materialModel = model.getModel(shading + 'Material');
    var detailTexture = materialModel.get('detailTexture');
    var uvRepeat = util_retrieve.firstNotNull(materialModel.get('textureTiling'), 1.0);
    var uvOffset = util_retrieve.firstNotNull(materialModel.get('textureOffset'), 0.0);
    if (typeof uvRepeat === 'number') {
        uvRepeat = [uvRepeat, uvRepeat];
    }
    if (typeof uvOffset === 'number') {
        uvOffset = [uvOffset, uvOffset];
    }
    var repeatParam = (uvRepeat[0] > 1 || uvRepeat[1] > 1) ? graphicGL.Texture.REPEAT : graphicGL.Texture.CLAMP_TO_EDGE;
    var textureOpt = {
        anisotropic: 8,
        wrapS: repeatParam,
        wrapT: repeatParam
    };
    if (shading === 'realistic') {
        var roughness = materialModel.get('roughness');
        var metalness = materialModel.get('metalness');
        if (metalness != null) {
            // Try to treat as a texture, TODO More check
            if (isNaN(metalness)) {
                material.setTextureImage('metalnessMap', metalness, api, textureOpt);
                metalness = util_retrieve.firstNotNull(materialModel.get('metalnessAdjust'), 0.5);
            }
        }
        else {
            // Default metalness.
            metalness = 0;
        }
        if (roughness != null) {
            // Try to treat as a texture, TODO More check
            if (isNaN(roughness)) {
                material.setTextureImage('roughnessMap', roughness, api, textureOpt);
                roughness = util_retrieve.firstNotNull(materialModel.get('roughnessAdjust'), 0.5);
            }
        }
        else {
            // Default roughness.
            roughness = 0.5;
        }
        var normalTextureVal = materialModel.get('normalTexture');
        material.setTextureImage('detailMap', detailTexture, api, textureOpt);
        material.setTextureImage('normalMap', normalTextureVal, api, textureOpt);
        material.set({
            roughness: roughness,
            metalness: metalness,
            detailUvRepeat: uvRepeat,
            detailUvOffset: uvOffset
        });
        // var normalTexture = material.get('normalMap');
        // if (normalTexture) {
            // PENDING
            // normalTexture.format = Texture.SRGB;
        // }
    }
    else if (shading === 'lambert') {
        material.setTextureImage('detailMap', detailTexture, api, textureOpt);
        material.set({
            detailUvRepeat: uvRepeat,
            detailUvOffset: uvOffset
        });
    }
    else if (shading === 'color') {
        material.setTextureImage('detailMap', detailTexture, api, textureOpt);
        material.set({
            detailUvRepeat: uvRepeat,
            detailUvOffset: uvOffset
        });
    }
    else if (shading === 'hatching') {
        var tams = materialModel.get('hatchingTextures') || [];
        if (tams.length < 6) {
            if (true) {
                console.error('Invalid hatchingTextures.');
            }
        }
        for (var i = 0; i < 6; i++) {
            material.setTextureImage('hatch' + (i + 1), tams[i], api, {
                anisotropic: 8,
                wrapS: graphicGL.Texture.REPEAT,
                wrapT: graphicGL.Texture.REPEAT
            });
        }
        material.set({
            detailUvRepeat: uvRepeat,
            detailUvOffset: uvOffset
        });
    }
};

graphicGL.updateVertexAnimation = function (
    mappingAttributes, previousMesh, currentMesh, seriesModel
) {
    var enableAnimation = seriesModel.get('animation');
    var duration = seriesModel.get('animationDurationUpdate');
    var easing = seriesModel.get('animationEasingUpdate');
    var shadowDepthMaterial = currentMesh.shadowDepthMaterial;

    if (enableAnimation && previousMesh && duration > 0
    // Only animate when bar count are not changed
    && previousMesh.geometry.vertexCount === currentMesh.geometry.vertexCount
    ) {
        currentMesh.material.define('vertex', 'VERTEX_ANIMATION');
        currentMesh.ignorePreZ = true;
        if (shadowDepthMaterial) {
            shadowDepthMaterial.define('vertex', 'VERTEX_ANIMATION');
        }
        for (var i = 0; i < mappingAttributes.length; i++) {
            currentMesh.geometry.attributes[mappingAttributes[i][0]].value =
            previousMesh.geometry.attributes[mappingAttributes[i][1]].value;
        }
        currentMesh.geometry.dirty();
        currentMesh.__percent = 0;
        currentMesh.material.set('percent', 0);
        currentMesh.stopAnimation();
        currentMesh.animate()
            .when(duration, {
                __percent: 1
            })
            .during(function () {
                currentMesh.material.set('percent', currentMesh.__percent);
                if (shadowDepthMaterial) {
                    shadowDepthMaterial.set('percent', currentMesh.__percent);
                }
            })
            .done(function () {
                currentMesh.ignorePreZ = false;
                currentMesh.material.undefine('vertex', 'VERTEX_ANIMATION');
                if (shadowDepthMaterial) {
                    shadowDepthMaterial.undefine('vertex', 'VERTEX_ANIMATION');
                }
            })
            .start(easing);
    }
    else {
        currentMesh.material.undefine('vertex', 'VERTEX_ANIMATION');
        if (shadowDepthMaterial) {
            shadowDepthMaterial.undefine('vertex', 'VERTEX_ANIMATION');
        }
    }
};

/* harmony default export */ const util_graphicGL = (graphicGL);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/animation/requestAnimationFrame.js
var requestAnimationFrame;
requestAnimationFrame = (typeof window !== 'undefined'
    && ((window.requestAnimationFrame && window.requestAnimationFrame.bind(window))
        || (window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window))
        || window.mozRequestAnimationFrame
        || window.webkitRequestAnimationFrame)) || function (func) {
    return setTimeout(func, 16);
};
/* harmony default export */ const animation_requestAnimationFrame = (requestAnimationFrame);

;// CONCATENATED MODULE: ./src/core/LayerGL.js
/**
 * Provide WebGL layer to zrender. Which is rendered on top of clay.
 *
 *
 * Relationship between zrender, LayerGL(renderer) and ViewGL(Scene, Camera, Viewport)
 *           zrender
 *           /     \
 *      LayerGL   LayerGL
 *    (renderer) (renderer)
 *      /     \
 *  ViewGL   ViewGL
 */







// PENDING, clay. notifier is same with zrender Eventful



/**
 * @constructor
 * @alias module:echarts-gl/core/LayerGL
 * @param {string} id Layer ID
 * @param {module:zrender/ZRender} zr
 */
var LayerGL = function (id, zr) {

    /**
     * Layer ID
     * @type {string}
     */
    this.id = id;

    /**
     * @type {module:zrender/ZRender}
     */
    this.zr = zr;

    /**
     * @type {clay.Renderer}
     */
    try {
        this.renderer = new src_Renderer({
            clearBit: 0,
            devicePixelRatio: zr.painter.dpr,
            preserveDrawingBuffer: true,
            // PENDING
            premultipliedAlpha: true
        });
        this.renderer.resize(zr.painter.getWidth(), zr.painter.getHeight());
    }
    catch (e) {
        this.renderer = null;
        this.dom = document.createElement('div');
        this.dom.style.cssText = 'position:absolute; left: 0; top: 0; right: 0; bottom: 0;';
        this.dom.className = 'ecgl-nowebgl';
        this.dom.innerHTML = 'Sorry, your browser does not support WebGL';

        console.error(e);
        return;
    }

    this.onglobalout = this.onglobalout.bind(this);
    zr.on('globalout', this.onglobalout);

    /**
     * Canvas dom for webgl rendering
     * @type {HTMLCanvasElement}
     */
    this.dom = this.renderer.canvas;
    var style = this.dom.style;
    style.position = 'absolute';
    style.left = '0';
    style.top = '0';

    /**
     * @type {Array.<clay.Scene>}
     */
    this.views = [];

    this._picking = new picking_RayPicking({
        renderer: this.renderer
    });

    this._viewsToDispose = [];

    /**
     * Current accumulating id.
     */
    this._accumulatingId = 0;

    this._zrEventProxy = new external_echarts_.graphic.Rect({
        shape: {x: -1, y: -1, width: 2, height: 2},
        // FIXME Better solution.
        __isGLToZRProxy: true
    });

    this._backgroundColor = null;

    this._disposed = false;
};

LayerGL.prototype.setUnpainted = function () {};

/**
 * @param {module:echarts-gl/core/ViewGL} view
 */
LayerGL.prototype.addView = function (view) {
    if (view.layer === this) {
        return;
    }
    // If needs to dispose in this layer. unmark it.
    var idx = this._viewsToDispose.indexOf(view);
    if (idx >= 0) {
        this._viewsToDispose.splice(idx, 1);
    }

    this.views.push(view);

    view.layer = this;

    var zr = this.zr;
    view.scene.traverse(function (node) {
        node.__zr = zr;
        if (node.addAnimatorsToZr) {
            node.addAnimatorsToZr(zr);
        }
    });
};

function removeFromZr(node) {
    var zr = node.__zr;
    node.__zr = null;
    if (zr && node.removeAnimatorsFromZr) {
        node.removeAnimatorsFromZr(zr);
    }
}
/**
 * @param {module:echarts-gl/core/ViewGL} view
 */
LayerGL.prototype.removeView = function (view) {
    if (view.layer !== this) {
        return;
    }

    var idx = this.views.indexOf(view);
    if (idx >= 0) {
        this.views.splice(idx, 1);
        view.scene.traverse(removeFromZr, this);
        view.layer = null;

        // Mark to dispose in this layer.
        this._viewsToDispose.push(view);
    }
};

/**
 * Remove all views
 */
LayerGL.prototype.removeViewsAll = function () {
    this.views.forEach(function (view) {
        view.scene.traverse(removeFromZr, this);
        view.layer = null;

        // Mark to dispose in this layer.
        this._viewsToDispose.push(view);
    }, this);

    this.views.length = 0;

};

/**
 * Resize the canvas and viewport, will be invoked by zrender
 * @param  {number} width
 * @param  {number} height
 */
LayerGL.prototype.resize = function (width, height) {
    var renderer = this.renderer;
    renderer.resize(width, height);
};

/**
 * Clear color and depth
 * @return {[type]} [description]
 */
LayerGL.prototype.clear = function () {
    var gl = this.renderer.gl;
    var clearColor = this._backgroundColor || [0, 0, 0, 0];
    gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
    gl.depthMask(true);
    gl.colorMask(true, true, true, true);
    gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
};

/**
 * Clear depth
 */
LayerGL.prototype.clearDepth = function () {
    var gl = this.renderer.gl;
    gl.clear(gl.DEPTH_BUFFER_BIT);
};

/**
 * Clear color
 */
LayerGL.prototype.clearColor = function () {
    var gl = this.renderer.gl;
    gl.clearColor(0, 0, 0, 0);
    gl.clear(gl.COLOR_BUFFER_BIT);
};

/**
 * Mark layer to refresh next tick
 */
LayerGL.prototype.needsRefresh = function () {
    this.zr.refresh();
};

/**
 * Refresh the layer, will be invoked by zrender
 */
LayerGL.prototype.refresh = function (bgColor) {

    this._backgroundColor = bgColor ? util_graphicGL.parseColor(bgColor) : [0, 0, 0, 0];
    this.renderer.clearColor = this._backgroundColor;

    for (var i = 0; i < this.views.length; i++) {
        this.views[i].prepareRender(this.renderer);
    }

    this._doRender(false);

    // Auto dispose unused resources on GPU, like program(shader), texture, geometry(buffers)
    this._trackAndClean();

    // Dispose trashed views
    for (var i = 0; i < this._viewsToDispose.length; i++) {
        this._viewsToDispose[i].dispose(this.renderer);
    }
    this._viewsToDispose.length = 0;

    this._startAccumulating();
};


LayerGL.prototype.renderToCanvas = function (ctx) {
    // PENDING will block the page
    this._startAccumulating(true);
    ctx.drawImage(this.dom, 0, 0, ctx.canvas.width, ctx.canvas.height);
};

LayerGL.prototype._doRender = function (accumulating) {
    this.clear();
    this.renderer.saveViewport();
    for (var i = 0; i < this.views.length; i++) {
        this.views[i].render(this.renderer, accumulating);
    }
    this.renderer.restoreViewport();
};

/**
 * Stop accumulating
 */
LayerGL.prototype._stopAccumulating = function () {
    this._accumulatingId = 0;
    clearTimeout(this._accumulatingTimeout);
};

var accumulatingId = 1;
/**
 * Start accumulating all the views.
 * Accumulating is for antialising and have more sampling in SSAO
 * @private
 */
LayerGL.prototype._startAccumulating = function (immediate) {
    var self = this;
    this._stopAccumulating();

    var needsAccumulate = false;
    for (var i = 0; i < this.views.length; i++) {
        needsAccumulate = this.views[i].needsAccumulate() || needsAccumulate;
    }
    if (!needsAccumulate) {
        return;
    }

    function accumulate(id) {
        if (!self._accumulatingId || id !== self._accumulatingId) {
            return;
        }

        var isFinished = true;
        for (var i = 0; i < self.views.length; i++) {
            isFinished = self.views[i].isAccumulateFinished() && needsAccumulate;
        }

        if (!isFinished) {
            self._doRender(true);

            if (immediate) {
                accumulate(id);
            }
            else {
                animation_requestAnimationFrame(function () {
                    accumulate(id);
                });
            }
        }
    }

    this._accumulatingId = accumulatingId++;

    if (immediate) {
        accumulate(self._accumulatingId);
    }
    else {
        this._accumulatingTimeout = setTimeout(function () {
            accumulate(self._accumulatingId);
        }, 50);
    }
};

LayerGL.prototype._trackAndClean = function () {
    var textureList = [];
    var geometriesList = [];

    // Mark all resources unused;
    if (this._textureList) {
        markUnused(this._textureList);
        markUnused(this._geometriesList);
    }

    for (var i = 0; i < this.views.length; i++) {
        collectResources(this.views[i].scene, textureList, geometriesList);
    }

    // Dispose those unsed resources.
    if (this._textureList) {
        checkAndDispose(this.renderer, this._textureList);
        checkAndDispose(this.renderer, this._geometriesList);
    }

    this._textureList = textureList;
    this._geometriesList = geometriesList;
};

function markUnused(resourceList) {
    for (var i = 0; i < resourceList.length; i++) {
        resourceList[i].__used__ = 0;
    }
}
function checkAndDispose(renderer, resourceList) {
    for (var i = 0; i < resourceList.length; i++) {
        if (!resourceList[i].__used__) {
            resourceList[i].dispose(renderer);
        }
    }
}
function updateUsed(resource, list) {
    resource.__used__ = resource.__used__ || 0;
    resource.__used__++;
    if (resource.__used__ === 1) {
        // Don't push to the list twice.
        list.push(resource);
    }
}
function collectResources(scene, textureResourceList, geometryResourceList) {
    var prevMaterial;
    var prevGeometry;
    scene.traverse(function (renderable) {
        if (renderable.isRenderable()) {
            var geometry = renderable.geometry;
            var material = renderable.material;

            // TODO optimize!!
            if (material !== prevMaterial) {
                var textureUniforms = material.getTextureUniforms();
                for (var u = 0; u < textureUniforms.length; u++) {
                    var uniformName = textureUniforms[u];
                    var val = material.uniforms[uniformName].value;
                    if (!val) {
                        continue;
                    }
                    if (val instanceof src_Texture) {
                        updateUsed(val, textureResourceList);
                    }
                    else if (val instanceof Array) {
                        for (var k = 0; k < val.length; k++) {
                            if (val[k] instanceof src_Texture) {
                                updateUsed(val[k], textureResourceList);
                            }
                        }
                    }
                }
            }
            if (geometry !== prevGeometry) {
                updateUsed(geometry, geometryResourceList);
            }

            prevMaterial = material;
            prevGeometry = geometry;
        }
    });

    for (var k = 0; k < scene.lights.length; k++) {
        // Track AmbientCubemap
        if (scene.lights[k].cubemap) {
            updateUsed(scene.lights[k].cubemap, textureResourceList);
        }
    }
}
/**
 * Dispose the layer
 */
LayerGL.prototype.dispose = function () {
    if (this._disposed) {
        return;
    }
    this._stopAccumulating();
    if (this._textureList) {
        markUnused(this._textureList);
        markUnused(this._geometriesList);
        checkAndDispose(this.renderer, this._textureList);
        checkAndDispose(this.renderer, this._geometriesList);
    }
    this.zr.off('globalout', this.onglobalout);
    this._disposed = true;
};

// Event handlers
LayerGL.prototype.onmousedown = function (e) {
    if (e.target && e.target.__isGLToZRProxy) {
        return;
    }

    e = e.event;
    var obj = this.pickObject(e.offsetX, e.offsetY);
    if (obj) {
        this._dispatchEvent('mousedown', e, obj);
        this._dispatchDataEvent('mousedown', e, obj);
    }

    this._downX = e.offsetX;
    this._downY = e.offsetY;
};

LayerGL.prototype.onmousemove = function (e) {
    if (e.target && e.target.__isGLToZRProxy) {
        return;
    }

    e = e.event;
    var obj = this.pickObject(e.offsetX, e.offsetY);

    var target = obj && obj.target;
    var lastHovered = this._hovered;
    this._hovered = obj;

    if (lastHovered && target !== lastHovered.target) {
        lastHovered.relatedTarget = target;
        this._dispatchEvent('mouseout', e, lastHovered);
        // this._dispatchDataEvent('mouseout', e, lastHovered);

        this.zr.setCursorStyle('default');
    }

    this._dispatchEvent('mousemove', e, obj);

    if (obj) {
        this.zr.setCursorStyle('pointer');

        if (!lastHovered || (target !== lastHovered.target)) {
            this._dispatchEvent('mouseover', e, obj);
            // this._dispatchDataEvent('mouseover', e, obj);
        }
    }

    this._dispatchDataEvent('mousemove', e, obj);
};

LayerGL.prototype.onmouseup = function (e) {
    if (e.target && e.target.__isGLToZRProxy) {
        return;
    }

    e = e.event;
    var obj = this.pickObject(e.offsetX, e.offsetY);

    if (obj) {
        this._dispatchEvent('mouseup', e, obj);
        this._dispatchDataEvent('mouseup', e, obj);
    }

    this._upX = e.offsetX;
    this._upY = e.offsetY;
};

LayerGL.prototype.onclick = LayerGL.prototype.dblclick = function (e) {
    if (e.target && e.target.__isGLToZRProxy) {
        return;
    }

    // Ignore click event if mouse moved
    var dx = this._upX - this._downX;
    var dy = this._upY - this._downY;
    if (Math.sqrt(dx * dx + dy * dy) > 20) {
        return;
    }

    e = e.event;
    var obj = this.pickObject(e.offsetX, e.offsetY);

    if (obj) {
        this._dispatchEvent(e.type, e, obj);
        this._dispatchDataEvent(e.type, e, obj);
    }

    // Try set depth of field onclick
    var result = this._clickToSetFocusPoint(e);
    if (result) {
        var success = result.view.setDOFFocusOnPoint(result.distance);
        if (success) {
            this.zr.refresh();
        }
    }
};

LayerGL.prototype._clickToSetFocusPoint = function (e) {
    var renderer = this.renderer;
    var oldViewport = renderer.viewport;
    for (var i = this.views.length - 1; i >= 0; i--) {
        var viewGL = this.views[i];
        if (viewGL.hasDOF() && viewGL.containPoint(e.offsetX, e.offsetY)) {
            this._picking.scene = viewGL.scene;
            this._picking.camera = viewGL.camera;
            // Only used for picking, renderer.setViewport will also invoke gl.viewport.
            // Set directly, PENDING.
            renderer.viewport = viewGL.viewport;
            var result = this._picking.pick(e.offsetX, e.offsetY, true);
            if (result) {
                result.view = viewGL;
                return result;
            }
        }
    }
    renderer.viewport = oldViewport;
};

LayerGL.prototype.onglobalout = function (e) {
    var lastHovered = this._hovered;
    if (lastHovered) {
        this._dispatchEvent('mouseout', e, {
            target: lastHovered.target
        });
    }
};

LayerGL.prototype.pickObject = function (x, y) {

    var output = [];
    var renderer = this.renderer;
    var oldViewport = renderer.viewport;
    for (var i = 0; i < this.views.length; i++) {
        var viewGL = this.views[i];
        if (viewGL.containPoint(x, y)) {
            this._picking.scene = viewGL.scene;
            this._picking.camera = viewGL.camera;
            // Only used for picking, renderer.setViewport will also invoke gl.viewport.
            // Set directly, PENDING.
            renderer.viewport = viewGL.viewport;
            this._picking.pickAll(x, y, output);
        }
    }
    renderer.viewport = oldViewport;
    output.sort(function (a, b) {
        return a.distance - b.distance;
    });
    return output[0];
};

LayerGL.prototype._dispatchEvent = function (eveName, originalEvent, newEvent) {
    if (!newEvent) {
        newEvent = {};
    }
    var current = newEvent.target;

    newEvent.cancelBubble = false;
    newEvent.event = originalEvent;
    newEvent.type = eveName;
    newEvent.offsetX = originalEvent.offsetX;
    newEvent.offsetY = originalEvent.offsetY;

    while (current) {
        current.trigger(eveName, newEvent);
        current = current.getParent();

        if (newEvent.cancelBubble) {
            break;
        }
    }

    this._dispatchToView(eveName, newEvent);
};

LayerGL.prototype._dispatchDataEvent = function (eveName, originalEvent, newEvent) {
    var mesh = newEvent && newEvent.target;

    var dataIndex = mesh && mesh.dataIndex;
    var seriesIndex = mesh && mesh.seriesIndex;
    // Custom event data
    var eventData = mesh && mesh.eventData;
    var elChangedInMouseMove = false;

    var eventProxy = this._zrEventProxy;
    eventProxy.x = originalEvent.offsetX;
    eventProxy.y = originalEvent.offsetY;
    eventProxy.update();

    var targetInfo = {
        target: eventProxy
    };
    const ecData = external_echarts_.helper.getECData(eventProxy);
    if (eveName === 'mousemove') {
        if (dataIndex != null) {
            if (dataIndex !== this._lastDataIndex) {
                if (parseInt(this._lastDataIndex, 10) >= 0) {
                    ecData.dataIndex = this._lastDataIndex;
                    ecData.seriesIndex = this._lastSeriesIndex;
                    // FIXME May cause double events.
                    this.zr.handler.dispatchToElement(targetInfo, 'mouseout', originalEvent);
                }
                elChangedInMouseMove = true;
            }
        }
        else if (eventData != null) {
            if (eventData !== this._lastEventData) {
                if (this._lastEventData != null) {
                    ecData.eventData = this._lastEventData;
                    // FIXME May cause double events.
                    this.zr.handler.dispatchToElement(targetInfo, 'mouseout', originalEvent);
                }
                elChangedInMouseMove = true;
            }
        }
        this._lastEventData = eventData;
        this._lastDataIndex = dataIndex;
        this._lastSeriesIndex = seriesIndex;
    }

    ecData.eventData = eventData;
    ecData.dataIndex = dataIndex;
    ecData.seriesIndex = seriesIndex;

    if (eventData != null || (parseInt(dataIndex, 10) >= 0 && parseInt(seriesIndex, 10) >= 0)) {
        this.zr.handler.dispatchToElement(targetInfo, eveName, originalEvent);

        if (elChangedInMouseMove) {
            this.zr.handler.dispatchToElement(targetInfo, 'mouseover', originalEvent);
        }
    }
};

LayerGL.prototype._dispatchToView = function (eventName, e) {
    for (var i = 0; i < this.views.length; i++) {
        if (this.views[i].containPoint(e.offsetX, e.offsetY)) {
            this.views[i].trigger(eventName, e);
        }
    }
};

Object.assign(LayerGL.prototype, mixin_notifier);

/* harmony default export */ const core_LayerGL = (LayerGL);
;// CONCATENATED MODULE: ./src/preprocessor/backwardCompat.js


var GL_SERIES = ['bar3D', 'line3D', 'map3D', 'scatter3D', 'surface', 'lines3D', 'scatterGL', 'scatter3D'];

function convertNormalEmphasis(option, optType) {
    if (option && option[optType] && (option[optType].normal || option[optType].emphasis)) {
        var normalOpt = option[optType].normal;
        var emphasisOpt = option[optType].emphasis;

        if (normalOpt) {
            option[optType] = normalOpt;
        }
        if (emphasisOpt) {
            option.emphasis = option.emphasis || {};
            option.emphasis[optType] = emphasisOpt;
        }
    }
}

function convertNormalEmphasisForEach(option) {
    convertNormalEmphasis(option, 'itemStyle');
    convertNormalEmphasis(option, 'lineStyle');
    convertNormalEmphasis(option, 'areaStyle');
    convertNormalEmphasis(option, 'label');
}

function removeTextStyleInAxis(axesOpt) {
    if (!axesOpt) {
        return;
    }
    if (!(axesOpt instanceof Array)) {
        axesOpt = [axesOpt];
    }
    external_echarts_.util.each(axesOpt, function (axisOpt) {
        if (axisOpt.axisLabel) {
            var labelOpt = axisOpt.axisLabel;
            Object.assign(labelOpt, labelOpt.textStyle);
            labelOpt.textStyle = null;
        }
    });
}

/* harmony default export */ function backwardCompat(option) {
    external_echarts_.util.each(option.series, function (series) {
        if (external_echarts_.util.indexOf(GL_SERIES, series.type) >= 0) {
            convertNormalEmphasisForEach(series);

            // Compatitable with original mapbox
            if (series.coordinateSystem === 'mapbox') {
                series.coordinateSystem = 'mapbox3D';
                option.mapbox3D = option.mapbox;
            }
        }
    });

    removeTextStyleInAxis(option.xAxis3D);
    removeTextStyleInAxis(option.yAxis3D);
    removeTextStyleInAxis(option.zAxis3D);
    removeTextStyleInAxis(option.grid3D);

    convertNormalEmphasis(option.geo3D);
};
;// CONCATENATED MODULE: ./src/echarts-gl.js
/**
 * echarts-gl
 * Extension pack of ECharts providing 3d plots and globe visualization
 *
 * Copyright (c) 2014, echarts-gl
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */





function EChartsGL (zr) {
    this._layers = {};

    this._zr = zr;
}

EChartsGL.prototype.update = function (ecModel, api) {
    var self = this;
    var zr = api.getZr();

    if (!zr.getWidth() || !zr.getHeight()) {
        console.warn('Dom has no width or height');
        return;
    }

    function getLayerGL(model) {
        // Disable auto sleep in gl layer.
        zr.setSleepAfterStill(0);

        var zlevel;
        // Host on coordinate system.
        if (model.coordinateSystem && model.coordinateSystem.model) {
            zlevel = model.get('zlevel');
        }
        else {
            zlevel = model.get('zlevel');
        }

        var layers = self._layers;
        var layerGL = layers[zlevel];
        if (!layerGL) {
            layerGL = layers[zlevel] = new core_LayerGL('gl-' + zlevel, zr);

            if (zr.painter.isSingleCanvas()) {
                layerGL.virtual = true;
                // If container is canvas, use image to represent LayerGL
                // FIXME Performance
                var img = new external_echarts_.graphic.Image({
                    z: 1e4,
                    style: {
                        image: layerGL.renderer.canvas
                    },
                    silent: true
                });
                layerGL.__hostImage = img;

                zr.add(img);
            }

            zr.painter.insertLayer(zlevel, layerGL);
        }
        if (layerGL.__hostImage) {
            layerGL.__hostImage.setStyle({
                width: layerGL.renderer.getWidth(),
                height: layerGL.renderer.getHeight()
            });
        }

        return layerGL;
    }

    function setSilent(groupGL, silent) {
        if (groupGL) {
            groupGL.traverse(function (mesh) {
                if (mesh.isRenderable && mesh.isRenderable()) {
                    mesh.ignorePicking = mesh.$ignorePicking != null
                        ? mesh.$ignorePicking : silent;
                }
            });
        }
    }

    for (var zlevel in this._layers) {
        this._layers[zlevel].removeViewsAll();
    }

    ecModel.eachComponent(function (componentType, componentModel) {
        if (componentType !== 'series') {
            var view = api.getViewOfComponentModel(componentModel);
            var coordSys = componentModel.coordinateSystem;
            // View with __ecgl__ flag is a echarts-gl component.
            if (view.__ecgl__) {
                var viewGL;
                if (coordSys) {
                    if (!coordSys.viewGL) {
                        console.error('Can\'t find viewGL in coordinateSystem of component ' + componentModel.id);
                        return;
                    }
                    viewGL = coordSys.viewGL;
                }
                else {
                    if (!componentModel.viewGL) {
                        console.error('Can\'t find viewGL of component ' + componentModel.id);
                        return;
                    }
                    viewGL = coordSys.viewGL;
                }

                var viewGL = coordSys.viewGL;
                var layerGL = getLayerGL(componentModel);

                layerGL.addView(viewGL);

                view.afterRender && view.afterRender(
                    componentModel, ecModel, api, layerGL
                );

                setSilent(view.groupGL, componentModel.get('silent'));
            }
        }
    });

    ecModel.eachSeries(function (seriesModel) {
        var chartView = api.getViewOfSeriesModel(seriesModel);
        var coordSys = seriesModel.coordinateSystem;
        if (chartView.__ecgl__) {
            if ((coordSys && !coordSys.viewGL) && !chartView.viewGL) {
                console.error('Can\'t find viewGL of series ' + chartView.id);
                return;
            }
            var viewGL = (coordSys && coordSys.viewGL) || chartView.viewGL;
            // TODO Check zlevel not same with component of coordinate system ?
            var layerGL = getLayerGL(seriesModel);
            layerGL.addView(viewGL);

            chartView.afterRender && chartView.afterRender(
                seriesModel, ecModel, api, layerGL
            );

            setSilent(chartView.groupGL, seriesModel.get('silent'));
        }
    });
};

// Hack original getRenderedCanvas. Will removed after new echarts released
// TODO

external_echarts_.registerPostInit(function (chart) {
    var zr = chart.getZr();
    var oldDispose = zr.painter.dispose;

    zr.painter.dispose = function () {
        this.eachOtherLayer(function (layer) {
            if (layer instanceof core_LayerGL) {
                layer.dispose();
            }
        });
        oldDispose.call(this);
    }
    zr.painter.getRenderedCanvas = function (opts) {
        opts = opts || {};
        if (this._singleCanvas) {
            return this._layers[0].dom;
        }

        var canvas = document.createElement('canvas');
        var dpr = opts.pixelRatio || this.dpr;
        canvas.width = this.getWidth() * dpr;
        canvas.height = this.getHeight() * dpr;
        var ctx = canvas.getContext('2d');
        ctx.dpr = dpr;

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (opts.backgroundColor) {
            ctx.fillStyle = opts.backgroundColor;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
        }

        var displayList = this.storage.getDisplayList(true);

        var scope = {};
        var zlevel;

        var self = this;
        function findAndDrawOtherLayer(smaller, larger) {
            var zlevelList = self._zlevelList;
            if (smaller == null) {
                smaller = -Infinity;
            }
            var intermediateLayer;
            for (var i = 0; i < zlevelList.length; i++) {
                var z = zlevelList[i];
                var layer = self._layers[z];
                if (!layer.__builtin__ && z > smaller && z < larger) {
                    intermediateLayer = layer;
                    break;
                }
            }
            if (intermediateLayer && intermediateLayer.renderToCanvas) {
                ctx.save();
                intermediateLayer.renderToCanvas(ctx);
                ctx.restore();
            }
        }
        var layer = {
            ctx: ctx
        };
        for (var i = 0; i < displayList.length; i++) {
            var el = displayList[i];

            if (el.zlevel !== zlevel) {
                findAndDrawOtherLayer(zlevel, el.zlevel);
                zlevel = el.zlevel;
            }
            this._doPaintEl(el, layer, true, null, scope);
        }

        findAndDrawOtherLayer(zlevel, Infinity);

        return canvas;
    };
});

external_echarts_.registerPostUpdate(function (ecModel, api) {
    var zr = api.getZr();

    var egl = zr.__egl = zr.__egl || new EChartsGL(zr);

    egl.update(ecModel, api);
});

external_echarts_.registerPreprocessor(backwardCompat);


/* harmony default export */ const echarts_gl = (EChartsGL);
;// CONCATENATED MODULE: ./src/component/common/componentViewControlMixin.js
/* harmony default export */ const componentViewControlMixin = ({
    defaultOption: {

        viewControl: {
            // perspective, orthographic.
            // TODO Isometric
            projection: 'perspective',
            // If rotate on on init
            autoRotate: false,
            // cw or ccw
            autoRotateDirection: 'cw',
            // Degree per second
            autoRotateSpeed: 10,

            // Start rotating after still for a given time
            // default is 3 seconds
            autoRotateAfterStill: 3,

            // Rotate, zoom damping.
            damping: 0.8,
            // Sensitivities for operations.
            // Can be array to set x,y respectively
            rotateSensitivity: 1,
            zoomSensitivity: 1,
            // Can be array to set x,y respectively
            panSensitivity: 1,
            // Which mouse button do rotate or pan
            panMouseButton: 'middle',
            rotateMouseButton: 'left',

            // Distance to the target
            // Only available when camera is perspective.
            distance: 150,
            // Min distance mouse can zoom in
            minDistance: 40,
            // Max distance mouse can zoom out
            maxDistance: 400,

            // Size of viewing volume.
            // Only available when camera is orthographic
            orthographicSize: 150,
            maxOrthographicSize: 400,
            minOrthographicSize: 20,

            // Center view point
            center: [0, 0, 0],
            // Alpha angle for top-down rotation
            // Positive to rotate to top.
            alpha: 0,
            // beta angle for left-right rotation
            // Positive to rotate to right.
            beta: 0,

            minAlpha: -90,
            maxAlpha: 90

            // minBeta: -Infinity
            // maxBeta: -Infinity
        }
    },

    setView: function (opts) {
        opts = opts || {};
        this.option.viewControl = this.option.viewControl || {};
        if (opts.alpha != null) {
            this.option.viewControl.alpha = opts.alpha;
        }
        if (opts.beta != null) {
            this.option.viewControl.beta = opts.beta;
        }
        if (opts.distance != null) {
            this.option.viewControl.distance = opts.distance;
        }
        if (opts.center != null) {
            this.option.viewControl.center = opts.center;
        }
    }
});
;// CONCATENATED MODULE: ./src/component/common/componentPostEffectMixin.js
/* harmony default export */ const componentPostEffectMixin = ({
    defaultOption: {
        // Post effect
        postEffect: {
            enable: false,

            bloom: {
                enable: true,
                intensity: 0.1
            },
            depthOfField: {
                enable: false,
                focalRange: 20,
                focalDistance: 50,
                blurRadius: 10,
                fstop: 2.8,
                quality: 'medium'
            },

            screenSpaceAmbientOcclusion: {
                enable: false,
                radius: 2,
                // low, medium, high, ultra
                quality: 'medium',
                intensity: 1
            },

            screenSpaceReflection: {
                enable: false,
                quality: 'medium',
                maxRoughness: 0.8
            },

            colorCorrection: {
                enable: true,

                exposure: 0,

                brightness: 0,

                contrast: 1,

                saturation: 1,

                lookupTexture: ''
            },

            edge: {
                enable: false
            },

            FXAA: {
                enable: false
            }
        },

        // Temporal super sampling when the picture is still.
        temporalSuperSampling: {
            // Only enabled when postEffect is enabled
            enable: 'auto'
        }
    }
});
;// CONCATENATED MODULE: ./src/component/common/componentLightMixin.js
/* harmony default export */ const componentLightMixin = ({
    defaultOption: {
        // Light is available when material.shading is not color
        light: {
            // Main light
            main: {
                shadow: false,
                // low, medium, high, ultra
                shadowQuality: 'high',

                color: '#fff',
                intensity: 1,

                alpha: 0,
                beta: 0
            },
            ambient: {
                color: '#fff',
                intensity: 0.2
            },
            ambientCubemap: {
                // Panorama environment texture,
                // Support .hdr and commmon web formats.
                texture: null,
                // Available when texture is hdr.
                exposure: 1,
                // Intensity for diffuse term
                diffuseIntensity: 0.5,
                // Intensity for specular term, only available when shading is realastic
                specularIntensity: 0.5
            }
        }
    }
});
;// CONCATENATED MODULE: ./src/component/grid3D/Grid3DModel.js





var Grid3DModel = external_echarts_.ComponentModel.extend({

    type: 'grid3D',

    dependencies: ['xAxis3D', 'yAxis3D', 'zAxis3D'],

    defaultOption: {

        show: true,

        zlevel: -10,

        // Layout used for viewport
        left: 0,
        top: 0,
        width: '100%',
        height: '100%',

        environment: 'auto',

        // Dimension of grid3D
        boxWidth: 100,
        boxHeight: 100,
        boxDepth: 100,

        // Common axis options.
        axisPointer: {
            show: true,
            lineStyle: {
                color: 'rgba(0, 0, 0, 0.8)',
                width: 1
            },

            label: {
                show: true,
                // (dimValue: number, value: Array) => string
                formatter: null,

                // TODO, Consider boxWidth
                margin: 8,
                // backgroundColor: '#ffbd67',
                // borderColor: '#000',
                // borderWidth: 0,

                textStyle: {
                    fontSize: 14,
                    color: '#fff',
                    backgroundColor: 'rgba(0,0,0,0.5)',
                    padding: 3,
                    borderRadius: 3
                }
            }
        },

        axisLine: {
            show: true,
            lineStyle: {
                color: '#333',
                width: 2,
                type: 'solid'
            }
        },

        axisTick: {
            show: true,
            inside: false,
            length: 3,
            lineStyle: {
                width: 1
            }
        },
        axisLabel: {
            show: true,
            inside: false,
            rotate: 0,
            margin: 8,
            textStyle: {
                fontSize: 12
            }
        },
        splitLine: {
            show: true,
            lineStyle: {
                color: ['#ccc'],
                width: 1,
                type: 'solid'
            }
        },
        splitArea: {
            show: false,
            areaStyle: {
                color: ['rgba(250,250,250,0.3)','rgba(200,200,200,0.3)']
            }
        },

        // Light options
        light: {
            main: {
                // Alpha angle for top-down rotation
                // Positive to rotate to top.
                alpha: 30,
                // beta angle for left-right rotation
                // Positive to rotate to right.
                beta: 40
            },
            ambient: {
                intensity: 0.4
            }
        },

        viewControl: {
            // Small damping for precise control.
            // damping: 0.1,

            // Alpha angle for top-down rotation
            // Positive to rotate to top.
            alpha: 20,
            // beta angle for left-right rotation
            // Positive to rotate to right.
            beta: 40,

            autoRotate: false,

            // Distance to the surface of grid3D.
            distance: 200,

            // Min distance to the surface of grid3D
            minDistance: 40,
            // Max distance to the surface of grid3D
            maxDistance: 400
        }
    }
});

external_echarts_.util.merge(Grid3DModel.prototype, componentViewControlMixin);
external_echarts_.util.merge(Grid3DModel.prototype, componentPostEffectMixin);
external_echarts_.util.merge(Grid3DModel.prototype, componentLightMixin);

/* harmony default export */ const grid3D_Grid3DModel = (Grid3DModel);


;// CONCATENATED MODULE: ./node_modules/zrender/node_modules/tslib/tslib.es6.js
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */

var extendStatics = function(d, b) {
    extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
    return extendStatics(d, b);
};

function __extends(d, b) {
    extendStatics(d, b);
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

var __assign = function() {
    __assign = Object.assign || function __assign(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
    }
    return __assign.apply(this, arguments);
}

function __rest(s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
}

function __decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}

function __param(paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
}

function __metadata(metadataKey, metadataValue) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
}

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

function __generator(thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
}

var __createBinding = Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
});

function __exportStar(m, o) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);
}

function __values(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}

function __read(o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
}

function __spread() {
    for (var ar = [], i = 0; i < arguments.length; i++)
        ar = ar.concat(__read(arguments[i]));
    return ar;
}

function __spreadArrays() {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};

function __await(v) {
    return this instanceof __await ? (this.v = v, this) : new __await(v);
}

function __asyncGenerator(thisArg, _arguments, generator) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var g = generator.apply(thisArg, _arguments || []), i, q = [];
    return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
    function fulfill(value) { resume("next", value); }
    function reject(value) { resume("throw", value); }
    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
}

function __asyncDelegator(o) {
    var i, p;
    return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
    function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
}

function __asyncValues(o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
}

function __makeTemplateObject(cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};

var __setModuleDefault = Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
};

function __importStar(mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
}

function __importDefault(mod) {
    return (mod && mod.__esModule) ? mod : { default: mod };
}

function __classPrivateFieldGet(receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
}

function __classPrivateFieldSet(receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/image.js

var globalImageCache = new lib_core_LRU(50);
function findExistImage(newImageOrSrc) {
    if (typeof newImageOrSrc === 'string') {
        var cachedImgObj = globalImageCache.get(newImageOrSrc);
        return cachedImgObj && cachedImgObj.image;
    }
    else {
        return newImageOrSrc;
    }
}
function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) {
    if (!newImageOrSrc) {
        return image;
    }
    else if (typeof newImageOrSrc === 'string') {
        if ((image && image.__zrImageSrc === newImageOrSrc) || !hostEl) {
            return image;
        }
        var cachedImgObj = globalImageCache.get(newImageOrSrc);
        var pendingWrap = { hostEl: hostEl, cb: onload, cbPayload: cbPayload };
        if (cachedImgObj) {
            image = cachedImgObj.image;
            !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);
        }
        else {
            image = new Image();
            image.onload = image.onerror = imageOnLoad;
            globalImageCache.put(newImageOrSrc, image.__cachedImgObj = {
                image: image,
                pending: [pendingWrap]
            });
            image.src = image.__zrImageSrc = newImageOrSrc;
        }
        return image;
    }
    else {
        return newImageOrSrc;
    }
}
function imageOnLoad() {
    var cachedImgObj = this.__cachedImgObj;
    this.onload = this.onerror = this.__cachedImgObj = null;
    for (var i = 0; i < cachedImgObj.pending.length; i++) {
        var pendingWrap = cachedImgObj.pending[i];
        var cb = pendingWrap.cb;
        cb && cb(this, pendingWrap.cbPayload);
        pendingWrap.hostEl.dirty();
    }
    cachedImgObj.pending.length = 0;
}
function isImageReady(image) {
    return image && image.width && image.height;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/matrix.js
function create() {
    return [1, 0, 0, 1, 0, 0];
}
function identity(out) {
    out[0] = 1;
    out[1] = 0;
    out[2] = 0;
    out[3] = 1;
    out[4] = 0;
    out[5] = 0;
    return out;
}
function copy(out, m) {
    out[0] = m[0];
    out[1] = m[1];
    out[2] = m[2];
    out[3] = m[3];
    out[4] = m[4];
    out[5] = m[5];
    return out;
}
function mul(out, m1, m2) {
    var out0 = m1[0] * m2[0] + m1[2] * m2[1];
    var out1 = m1[1] * m2[0] + m1[3] * m2[1];
    var out2 = m1[0] * m2[2] + m1[2] * m2[3];
    var out3 = m1[1] * m2[2] + m1[3] * m2[3];
    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
    out[0] = out0;
    out[1] = out1;
    out[2] = out2;
    out[3] = out3;
    out[4] = out4;
    out[5] = out5;
    return out;
}
function translate(out, a, v) {
    out[0] = a[0];
    out[1] = a[1];
    out[2] = a[2];
    out[3] = a[3];
    out[4] = a[4] + v[0];
    out[5] = a[5] + v[1];
    return out;
}
function rotate(out, a, rad) {
    var aa = a[0];
    var ac = a[2];
    var atx = a[4];
    var ab = a[1];
    var ad = a[3];
    var aty = a[5];
    var st = Math.sin(rad);
    var ct = Math.cos(rad);
    out[0] = aa * ct + ab * st;
    out[1] = -aa * st + ab * ct;
    out[2] = ac * ct + ad * st;
    out[3] = -ac * st + ct * ad;
    out[4] = ct * atx + st * aty;
    out[5] = ct * aty - st * atx;
    return out;
}
function scale(out, a, v) {
    var vx = v[0];
    var vy = v[1];
    out[0] = a[0] * vx;
    out[1] = a[1] * vy;
    out[2] = a[2] * vx;
    out[3] = a[3] * vy;
    out[4] = a[4] * vx;
    out[5] = a[5] * vy;
    return out;
}
function matrix_invert(out, a) {
    var aa = a[0];
    var ac = a[2];
    var atx = a[4];
    var ab = a[1];
    var ad = a[3];
    var aty = a[5];
    var det = aa * ad - ab * ac;
    if (!det) {
        return null;
    }
    det = 1.0 / det;
    out[0] = ad * det;
    out[1] = -ab * det;
    out[2] = -ac * det;
    out[3] = aa * det;
    out[4] = (ac * aty - ad * atx) * det;
    out[5] = (ab * atx - aa * aty) * det;
    return out;
}
function matrix_clone(a) {
    var b = create();
    copy(b, a);
    return b;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/Point.js
var Point_Point = (function () {
    function Point(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    }
    Point.prototype.copy = function (other) {
        this.x = other.x;
        this.y = other.y;
        return this;
    };
    Point.prototype.clone = function () {
        return new Point(this.x, this.y);
    };
    Point.prototype.set = function (x, y) {
        this.x = x;
        this.y = y;
        return this;
    };
    Point.prototype.equal = function (other) {
        return other.x === this.x && other.y === this.y;
    };
    Point.prototype.add = function (other) {
        this.x += other.x;
        this.y += other.y;
        return this;
    };
    Point.prototype.scale = function (scalar) {
        this.x *= scalar;
        this.y *= scalar;
    };
    Point.prototype.scaleAndAdd = function (other, scalar) {
        this.x += other.x * scalar;
        this.y += other.y * scalar;
    };
    Point.prototype.sub = function (other) {
        this.x -= other.x;
        this.y -= other.y;
        return this;
    };
    Point.prototype.dot = function (other) {
        return this.x * other.x + this.y * other.y;
    };
    Point.prototype.len = function () {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    };
    Point.prototype.lenSquare = function () {
        return this.x * this.x + this.y * this.y;
    };
    Point.prototype.normalize = function () {
        var len = this.len();
        this.x /= len;
        this.y /= len;
        return this;
    };
    Point.prototype.distance = function (other) {
        var dx = this.x - other.x;
        var dy = this.y - other.y;
        return Math.sqrt(dx * dx + dy * dy);
    };
    Point.prototype.distanceSquare = function (other) {
        var dx = this.x - other.x;
        var dy = this.y - other.y;
        return dx * dx + dy * dy;
    };
    Point.prototype.negate = function () {
        this.x = -this.x;
        this.y = -this.y;
        return this;
    };
    Point.prototype.transform = function (m) {
        if (!m) {
            return;
        }
        var x = this.x;
        var y = this.y;
        this.x = m[0] * x + m[2] * y + m[4];
        this.y = m[1] * x + m[3] * y + m[5];
        return this;
    };
    Point.prototype.toArray = function (out) {
        out[0] = this.x;
        out[1] = this.y;
        return out;
    };
    Point.prototype.fromArray = function (input) {
        this.x = input[0];
        this.y = input[1];
    };
    Point.set = function (p, x, y) {
        p.x = x;
        p.y = y;
    };
    Point.copy = function (p, p2) {
        p.x = p2.x;
        p.y = p2.y;
    };
    Point.len = function (p) {
        return Math.sqrt(p.x * p.x + p.y * p.y);
    };
    Point.lenSquare = function (p) {
        return p.x * p.x + p.y * p.y;
    };
    Point.dot = function (p0, p1) {
        return p0.x * p1.x + p0.y * p1.y;
    };
    Point.add = function (out, p0, p1) {
        out.x = p0.x + p1.x;
        out.y = p0.y + p1.y;
    };
    Point.sub = function (out, p0, p1) {
        out.x = p0.x - p1.x;
        out.y = p0.y - p1.y;
    };
    Point.scale = function (out, p0, scalar) {
        out.x = p0.x * scalar;
        out.y = p0.y * scalar;
    };
    Point.scaleAndAdd = function (out, p0, p1, scalar) {
        out.x = p0.x + p1.x * scalar;
        out.y = p0.y + p1.y * scalar;
    };
    Point.lerp = function (out, p0, p1, t) {
        var onet = 1 - t;
        out.x = onet * p0.x + t * p1.x;
        out.y = onet * p0.y + t * p1.y;
    };
    return Point;
}());
/* harmony default export */ const core_Point = (Point_Point);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/BoundingRect.js


var BoundingRect_mathMin = Math.min;
var BoundingRect_mathMax = Math.max;
var lt = new core_Point();
var rb = new core_Point();
var lb = new core_Point();
var rt = new core_Point();
var minTv = new core_Point();
var maxTv = new core_Point();
var BoundingRect = (function () {
    function BoundingRect(x, y, width, height) {
        if (width < 0) {
            x = x + width;
            width = -width;
        }
        if (height < 0) {
            y = y + height;
            height = -height;
        }
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
    }
    BoundingRect.prototype.union = function (other) {
        var x = BoundingRect_mathMin(other.x, this.x);
        var y = BoundingRect_mathMin(other.y, this.y);
        if (isFinite(this.x) && isFinite(this.width)) {
            this.width = BoundingRect_mathMax(other.x + other.width, this.x + this.width) - x;
        }
        else {
            this.width = other.width;
        }
        if (isFinite(this.y) && isFinite(this.height)) {
            this.height = BoundingRect_mathMax(other.y + other.height, this.y + this.height) - y;
        }
        else {
            this.height = other.height;
        }
        this.x = x;
        this.y = y;
    };
    BoundingRect.prototype.applyTransform = function (m) {
        BoundingRect.applyTransform(this, this, m);
    };
    BoundingRect.prototype.calculateTransform = function (b) {
        var a = this;
        var sx = b.width / a.width;
        var sy = b.height / a.height;
        var m = create();
        translate(m, m, [-a.x, -a.y]);
        scale(m, m, [sx, sy]);
        translate(m, m, [b.x, b.y]);
        return m;
    };
    BoundingRect.prototype.intersect = function (b, mtv) {
        if (!b) {
            return false;
        }
        if (!(b instanceof BoundingRect)) {
            b = BoundingRect.create(b);
        }
        var a = this;
        var ax0 = a.x;
        var ax1 = a.x + a.width;
        var ay0 = a.y;
        var ay1 = a.y + a.height;
        var bx0 = b.x;
        var bx1 = b.x + b.width;
        var by0 = b.y;
        var by1 = b.y + b.height;
        var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
        if (mtv) {
            var dMin = Infinity;
            var dMax = 0;
            var d0 = Math.abs(ax1 - bx0);
            var d1 = Math.abs(bx1 - ax0);
            var d2 = Math.abs(ay1 - by0);
            var d3 = Math.abs(by1 - ay0);
            var dx = Math.min(d0, d1);
            var dy = Math.min(d2, d3);
            if (ax1 < bx0 || bx1 < ax0) {
                if (dx > dMax) {
                    dMax = dx;
                    if (d0 < d1) {
                        core_Point.set(maxTv, -d0, 0);
                    }
                    else {
                        core_Point.set(maxTv, d1, 0);
                    }
                }
            }
            else {
                if (dx < dMin) {
                    dMin = dx;
                    if (d0 < d1) {
                        core_Point.set(minTv, d0, 0);
                    }
                    else {
                        core_Point.set(minTv, -d1, 0);
                    }
                }
            }
            if (ay1 < by0 || by1 < ay0) {
                if (dy > dMax) {
                    dMax = dy;
                    if (d2 < d3) {
                        core_Point.set(maxTv, 0, -d2);
                    }
                    else {
                        core_Point.set(maxTv, 0, d3);
                    }
                }
            }
            else {
                if (dx < dMin) {
                    dMin = dx;
                    if (d2 < d3) {
                        core_Point.set(minTv, 0, d2);
                    }
                    else {
                        core_Point.set(minTv, 0, -d3);
                    }
                }
            }
        }
        if (mtv) {
            core_Point.copy(mtv, overlap ? minTv : maxTv);
        }
        return overlap;
    };
    BoundingRect.prototype.contain = function (x, y) {
        var rect = this;
        return x >= rect.x
            && x <= (rect.x + rect.width)
            && y >= rect.y
            && y <= (rect.y + rect.height);
    };
    BoundingRect.prototype.clone = function () {
        return new BoundingRect(this.x, this.y, this.width, this.height);
    };
    BoundingRect.prototype.copy = function (other) {
        BoundingRect.copy(this, other);
    };
    BoundingRect.prototype.plain = function () {
        return {
            x: this.x,
            y: this.y,
            width: this.width,
            height: this.height
        };
    };
    BoundingRect.prototype.isFinite = function () {
        return isFinite(this.x)
            && isFinite(this.y)
            && isFinite(this.width)
            && isFinite(this.height);
    };
    BoundingRect.prototype.isZero = function () {
        return this.width === 0 || this.height === 0;
    };
    BoundingRect.create = function (rect) {
        return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
    };
    BoundingRect.copy = function (target, source) {
        target.x = source.x;
        target.y = source.y;
        target.width = source.width;
        target.height = source.height;
    };
    BoundingRect.applyTransform = function (target, source, m) {
        if (!m) {
            if (target !== source) {
                BoundingRect.copy(target, source);
            }
            return;
        }
        if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) {
            var sx = m[0];
            var sy = m[3];
            var tx = m[4];
            var ty = m[5];
            target.x = source.x * sx + tx;
            target.y = source.y * sy + ty;
            target.width = source.width * sx;
            target.height = source.height * sy;
            if (target.width < 0) {
                target.x += target.width;
                target.width = -target.width;
            }
            if (target.height < 0) {
                target.y += target.height;
                target.height = -target.height;
            }
            return;
        }
        lt.x = lb.x = source.x;
        lt.y = rt.y = source.y;
        rb.x = rt.x = source.x + source.width;
        rb.y = lb.y = source.y + source.height;
        lt.transform(m);
        rt.transform(m);
        rb.transform(m);
        lb.transform(m);
        target.x = BoundingRect_mathMin(lt.x, rb.x, lb.x, rt.x);
        target.y = BoundingRect_mathMin(lt.y, rb.y, lb.y, rt.y);
        var maxX = BoundingRect_mathMax(lt.x, rb.x, lb.x, rt.x);
        var maxY = BoundingRect_mathMax(lt.y, rb.y, lb.y, rt.y);
        target.width = maxX - target.x;
        target.height = maxY - target.y;
    };
    return BoundingRect;
}());
/* harmony default export */ const core_BoundingRect = (BoundingRect);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/text.js



var textWidthCache = {};
var DEFAULT_FONT = '12px sans-serif';
var _ctx;
var _cachedFont;
function defaultMeasureText(text, font) {
    if (!_ctx) {
        _ctx = createCanvas().getContext('2d');
    }
    if (_cachedFont !== font) {
        _cachedFont = _ctx.font = font || DEFAULT_FONT;
    }
    return _ctx.measureText(text);
}
var text_methods = {
    measureText: defaultMeasureText
};
function text_$override(name, fn) {
    text_methods[name] = fn;
}
function getWidth(text, font) {
    font = font || DEFAULT_FONT;
    var cacheOfFont = textWidthCache[font];
    if (!cacheOfFont) {
        cacheOfFont = textWidthCache[font] = new lib_core_LRU(500);
    }
    var width = cacheOfFont.get(text);
    if (width == null) {
        width = text_methods.measureText(text, font).width;
        cacheOfFont.put(text, width);
    }
    return width;
}
function innerGetBoundingRect(text, font, textAlign, textBaseline) {
    var width = getWidth(text, font);
    var height = getLineHeight(font);
    var x = adjustTextX(0, width, textAlign);
    var y = adjustTextY(0, height, textBaseline);
    var rect = new core_BoundingRect(x, y, width, height);
    return rect;
}
function getBoundingRect(text, font, textAlign, textBaseline) {
    var textLines = ((text || '') + '').split('\n');
    var len = textLines.length;
    if (len === 1) {
        return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline);
    }
    else {
        var uniondRect = new core_BoundingRect(0, 0, 0, 0);
        for (var i = 0; i < textLines.length; i++) {
            var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline);
            i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect);
        }
        return uniondRect;
    }
}
function adjustTextX(x, width, textAlign) {
    if (textAlign === 'right') {
        x -= width;
    }
    else if (textAlign === 'center') {
        x -= width / 2;
    }
    return x;
}
function adjustTextY(y, height, verticalAlign) {
    if (verticalAlign === 'middle') {
        y -= height / 2;
    }
    else if (verticalAlign === 'bottom') {
        y -= height;
    }
    return y;
}
function getLineHeight(font) {
    return getWidth('国', font);
}
function measureText(text, font) {
    return text_methods.measureText(text, font);
}
function parsePercent(value, maxValue) {
    if (typeof value === 'string') {
        if (value.lastIndexOf('%') >= 0) {
            return parseFloat(value) / 100 * maxValue;
        }
        return parseFloat(value);
    }
    return value;
}
function calculateTextPosition(out, opts, rect) {
    var textPosition = opts.position || 'inside';
    var distance = opts.distance != null ? opts.distance : 5;
    var height = rect.height;
    var width = rect.width;
    var halfHeight = height / 2;
    var x = rect.x;
    var y = rect.y;
    var textAlign = 'left';
    var textVerticalAlign = 'top';
    if (textPosition instanceof Array) {
        x += parsePercent(textPosition[0], rect.width);
        y += parsePercent(textPosition[1], rect.height);
        textAlign = null;
        textVerticalAlign = null;
    }
    else {
        switch (textPosition) {
            case 'left':
                x -= distance;
                y += halfHeight;
                textAlign = 'right';
                textVerticalAlign = 'middle';
                break;
            case 'right':
                x += distance + width;
                y += halfHeight;
                textVerticalAlign = 'middle';
                break;
            case 'top':
                x += width / 2;
                y -= distance;
                textAlign = 'center';
                textVerticalAlign = 'bottom';
                break;
            case 'bottom':
                x += width / 2;
                y += height + distance;
                textAlign = 'center';
                break;
            case 'inside':
                x += width / 2;
                y += halfHeight;
                textAlign = 'center';
                textVerticalAlign = 'middle';
                break;
            case 'insideLeft':
                x += distance;
                y += halfHeight;
                textVerticalAlign = 'middle';
                break;
            case 'insideRight':
                x += width - distance;
                y += halfHeight;
                textAlign = 'right';
                textVerticalAlign = 'middle';
                break;
            case 'insideTop':
                x += width / 2;
                y += distance;
                textAlign = 'center';
                break;
            case 'insideBottom':
                x += width / 2;
                y += height - distance;
                textAlign = 'center';
                textVerticalAlign = 'bottom';
                break;
            case 'insideTopLeft':
                x += distance;
                y += distance;
                break;
            case 'insideTopRight':
                x += width - distance;
                y += distance;
                textAlign = 'right';
                break;
            case 'insideBottomLeft':
                x += distance;
                y += height - distance;
                textVerticalAlign = 'bottom';
                break;
            case 'insideBottomRight':
                x += width - distance;
                y += height - distance;
                textAlign = 'right';
                textVerticalAlign = 'bottom';
                break;
        }
    }
    out = out || {};
    out.x = x;
    out.y = y;
    out.align = textAlign;
    out.verticalAlign = textVerticalAlign;
    return out;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/parseText.js



var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;
function truncateText(text, containerWidth, font, ellipsis, options) {
    if (!containerWidth) {
        return '';
    }
    var textLines = (text + '').split('\n');
    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);
    for (var i = 0, len = textLines.length; i < len; i++) {
        textLines[i] = truncateSingleLine(textLines[i], options);
    }
    return textLines.join('\n');
}
function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
    options = options || {};
    var preparedOpts = util_extend({}, options);
    preparedOpts.font = font;
    ellipsis = retrieve2(ellipsis, '...');
    preparedOpts.maxIterations = retrieve2(options.maxIterations, 2);
    var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0);
    preparedOpts.cnCharWidth = getWidth('国', font);
    var ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font);
    preparedOpts.placeholder = retrieve2(options.placeholder, '');
    var contentWidth = containerWidth = Math.max(0, containerWidth - 1);
    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
        contentWidth -= ascCharWidth;
    }
    var ellipsisWidth = getWidth(ellipsis, font);
    if (ellipsisWidth > contentWidth) {
        ellipsis = '';
        ellipsisWidth = 0;
    }
    contentWidth = containerWidth - ellipsisWidth;
    preparedOpts.ellipsis = ellipsis;
    preparedOpts.ellipsisWidth = ellipsisWidth;
    preparedOpts.contentWidth = contentWidth;
    preparedOpts.containerWidth = containerWidth;
    return preparedOpts;
}
function truncateSingleLine(textLine, options) {
    var containerWidth = options.containerWidth;
    var font = options.font;
    var contentWidth = options.contentWidth;
    if (!containerWidth) {
        return '';
    }
    var lineWidth = getWidth(textLine, font);
    if (lineWidth <= containerWidth) {
        return textLine;
    }
    for (var j = 0;; j++) {
        if (lineWidth <= contentWidth || j >= options.maxIterations) {
            textLine += options.ellipsis;
            break;
        }
        var subLength = j === 0
            ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth)
            : lineWidth > 0
                ? Math.floor(textLine.length * contentWidth / lineWidth)
                : 0;
        textLine = textLine.substr(0, subLength);
        lineWidth = getWidth(textLine, font);
    }
    if (textLine === '') {
        textLine = options.placeholder;
    }
    return textLine;
}
function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
    var width = 0;
    var i = 0;
    for (var len = text.length; i < len && width < contentWidth; i++) {
        var charCode = text.charCodeAt(i);
        width += (0 <= charCode && charCode <= 127) ? ascCharWidth : cnCharWidth;
    }
    return i;
}
function parsePlainText(text, style) {
    text != null && (text += '');
    var overflow = style.overflow;
    var padding = style.padding;
    var font = style.font;
    var truncate = overflow === 'truncate';
    var calculatedLineHeight = getLineHeight(font);
    var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight);
    var truncateLineOverflow = style.lineOverflow === 'truncate';
    var width = style.width;
    var lines;
    if (width != null && overflow === 'break' || overflow === 'breakAll') {
        lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : [];
    }
    else {
        lines = text ? text.split('\n') : [];
    }
    var contentHeight = lines.length * lineHeight;
    var height = retrieve2(style.height, contentHeight);
    if (contentHeight > height && truncateLineOverflow) {
        var lineCount = Math.floor(height / lineHeight);
        lines = lines.slice(0, lineCount);
    }
    var outerHeight = height;
    var outerWidth = width;
    if (padding) {
        outerHeight += padding[0] + padding[2];
        if (outerWidth != null) {
            outerWidth += padding[1] + padding[3];
        }
    }
    if (text && truncate && outerWidth != null) {
        var options = prepareTruncateOptions(width, font, style.ellipsis, {
            minChar: style.truncateMinChar,
            placeholder: style.placeholder
        });
        for (var i = 0; i < lines.length; i++) {
            lines[i] = truncateSingleLine(lines[i], options);
        }
    }
    if (width == null) {
        var maxWidth = 0;
        for (var i = 0; i < lines.length; i++) {
            maxWidth = Math.max(getWidth(lines[i], font), maxWidth);
        }
        width = maxWidth;
    }
    return {
        lines: lines,
        height: height,
        outerHeight: outerHeight,
        lineHeight: lineHeight,
        calculatedLineHeight: calculatedLineHeight,
        contentHeight: contentHeight,
        width: width
    };
}
var RichTextToken = (function () {
    function RichTextToken() {
    }
    return RichTextToken;
}());
var RichTextLine = (function () {
    function RichTextLine(tokens) {
        this.tokens = [];
        if (tokens) {
            this.tokens = tokens;
        }
    }
    return RichTextLine;
}());
var RichTextContentBlock = (function () {
    function RichTextContentBlock() {
        this.width = 0;
        this.height = 0;
        this.contentWidth = 0;
        this.contentHeight = 0;
        this.outerWidth = 0;
        this.outerHeight = 0;
        this.lines = [];
    }
    return RichTextContentBlock;
}());

function parseRichText(text, style) {
    var contentBlock = new RichTextContentBlock();
    text != null && (text += '');
    if (!text) {
        return contentBlock;
    }
    var topWidth = style.width;
    var topHeight = style.height;
    var overflow = style.overflow;
    var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null
        ? { width: topWidth, accumWidth: 0, breakAll: overflow === 'breakAll' }
        : null;
    var lastIndex = STYLE_REG.lastIndex = 0;
    var result;
    while ((result = STYLE_REG.exec(text)) != null) {
        var matchedIndex = result.index;
        if (matchedIndex > lastIndex) {
            pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo);
        }
        pushTokens(contentBlock, result[2], style, wrapInfo, result[1]);
        lastIndex = STYLE_REG.lastIndex;
    }
    if (lastIndex < text.length) {
        pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo);
    }
    var pendingList = [];
    var calculatedHeight = 0;
    var calculatedWidth = 0;
    var stlPadding = style.padding;
    var truncate = overflow === 'truncate';
    var truncateLine = style.lineOverflow === 'truncate';
    function finishLine(line, lineWidth, lineHeight) {
        line.width = lineWidth;
        line.lineHeight = lineHeight;
        calculatedHeight += lineHeight;
        calculatedWidth = Math.max(calculatedWidth, lineWidth);
    }
    outer: for (var i = 0; i < contentBlock.lines.length; i++) {
        var line = contentBlock.lines[i];
        var lineHeight = 0;
        var lineWidth = 0;
        for (var j = 0; j < line.tokens.length; j++) {
            var token = line.tokens[j];
            var tokenStyle = token.styleName && style.rich[token.styleName] || {};
            var textPadding = token.textPadding = tokenStyle.padding;
            var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0;
            var font = token.font = tokenStyle.font || style.font;
            token.contentHeight = getLineHeight(font);
            var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight);
            token.innerHeight = tokenHeight;
            textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
            token.height = tokenHeight;
            token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight);
            token.align = tokenStyle && tokenStyle.align || style.align;
            token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle';
            if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) {
                if (j > 0) {
                    line.tokens = line.tokens.slice(0, j);
                    finishLine(line, lineWidth, lineHeight);
                    contentBlock.lines = contentBlock.lines.slice(0, i + 1);
                }
                else {
                    contentBlock.lines = contentBlock.lines.slice(0, i);
                }
                break outer;
            }
            var styleTokenWidth = tokenStyle.width;
            var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto';
            if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') {
                token.percentWidth = styleTokenWidth;
                pendingList.push(token);
                token.contentWidth = getWidth(token.text, font);
            }
            else {
                if (tokenWidthNotSpecified) {
                    var textBackgroundColor = tokenStyle.backgroundColor;
                    var bgImg = textBackgroundColor && textBackgroundColor.image;
                    if (bgImg) {
                        bgImg = findExistImage(bgImg);
                        if (isImageReady(bgImg)) {
                            token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height);
                        }
                    }
                }
                var remainTruncWidth = truncate && topWidth != null
                    ? topWidth - lineWidth : null;
                if (remainTruncWidth != null && remainTruncWidth < token.width) {
                    if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) {
                        token.text = '';
                        token.width = token.contentWidth = 0;
                    }
                    else {
                        token.text = truncateText(token.text, remainTruncWidth - paddingH, font, style.ellipsis, { minChar: style.truncateMinChar });
                        token.width = token.contentWidth = getWidth(token.text, font);
                    }
                }
                else {
                    token.contentWidth = getWidth(token.text, font);
                }
            }
            token.width += paddingH;
            lineWidth += token.width;
            tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));
        }
        finishLine(line, lineWidth, lineHeight);
    }
    contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth);
    contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight);
    contentBlock.contentHeight = calculatedHeight;
    contentBlock.contentWidth = calculatedWidth;
    if (stlPadding) {
        contentBlock.outerWidth += stlPadding[1] + stlPadding[3];
        contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
    }
    for (var i = 0; i < pendingList.length; i++) {
        var token = pendingList[i];
        var percentWidth = token.percentWidth;
        token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width;
    }
    return contentBlock;
}
function pushTokens(block, str, style, wrapInfo, styleName) {
    var isEmptyStr = str === '';
    var tokenStyle = styleName && style.rich[styleName] || {};
    var lines = block.lines;
    var font = tokenStyle.font || style.font;
    var newLine = false;
    var strLines;
    var linesWidths;
    if (wrapInfo) {
        var tokenPadding = tokenStyle.padding;
        var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0;
        if (tokenStyle.width != null && tokenStyle.width !== 'auto') {
            var outerWidth_1 = parsePercent(tokenStyle.width, wrapInfo.width) + tokenPaddingH;
            if (lines.length > 0) {
                if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) {
                    strLines = str.split('\n');
                    newLine = true;
                }
            }
            wrapInfo.accumWidth = outerWidth_1;
        }
        else {
            var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth);
            wrapInfo.accumWidth = res.accumWidth + tokenPaddingH;
            linesWidths = res.linesWidths;
            strLines = res.lines;
        }
    }
    else {
        strLines = str.split('\n');
    }
    for (var i = 0; i < strLines.length; i++) {
        var text = strLines[i];
        var token = new RichTextToken();
        token.styleName = styleName;
        token.text = text;
        token.isLineHolder = !text && !isEmptyStr;
        if (typeof tokenStyle.width === 'number') {
            token.width = tokenStyle.width;
        }
        else {
            token.width = linesWidths
                ? linesWidths[i]
                : getWidth(text, font);
        }
        if (!i && !newLine) {
            var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens;
            var tokensLen = tokens.length;
            (tokensLen === 1 && tokens[0].isLineHolder)
                ? (tokens[0] = token)
                : ((text || !tokensLen || isEmptyStr) && tokens.push(token));
        }
        else {
            lines.push(new RichTextLine([token]));
        }
    }
}
function isLatin(ch) {
    var code = ch.charCodeAt(0);
    return code >= 0x21 && code <= 0xFF;
}
var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) {
    obj[ch] = true;
    return obj;
}, {});
function isWordBreakChar(ch) {
    if (isLatin(ch)) {
        if (breakCharMap[ch]) {
            return true;
        }
        return false;
    }
    return true;
}
function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
    var lines = [];
    var linesWidths = [];
    var line = '';
    var currentWord = '';
    var currentWordWidth = 0;
    var accumWidth = 0;
    for (var i = 0; i < text.length; i++) {
        var ch = text.charAt(i);
        if (ch === '\n') {
            if (currentWord) {
                line += currentWord;
                accumWidth += currentWordWidth;
            }
            lines.push(line);
            linesWidths.push(accumWidth);
            line = '';
            currentWord = '';
            currentWordWidth = 0;
            accumWidth = 0;
            continue;
        }
        var chWidth = getWidth(ch, font);
        var inWord = isBreakAll ? false : !isWordBreakChar(ch);
        if (!lines.length
            ? lastAccumWidth + accumWidth + chWidth > lineWidth
            : accumWidth + chWidth > lineWidth) {
            if (!accumWidth) {
                if (inWord) {
                    lines.push(currentWord);
                    linesWidths.push(currentWordWidth);
                    currentWord = ch;
                    currentWordWidth = chWidth;
                }
                else {
                    lines.push(ch);
                    linesWidths.push(chWidth);
                }
            }
            else if (line || currentWord) {
                if (inWord) {
                    if (!line) {
                        line = currentWord;
                        currentWord = '';
                        currentWordWidth = 0;
                        accumWidth = currentWordWidth;
                    }
                    lines.push(line);
                    linesWidths.push(accumWidth - currentWordWidth);
                    currentWord += ch;
                    currentWordWidth += chWidth;
                    line = '';
                    accumWidth = currentWordWidth;
                }
                else {
                    if (currentWord) {
                        line += currentWord;
                        accumWidth += currentWordWidth;
                        currentWord = '';
                        currentWordWidth = 0;
                    }
                    lines.push(line);
                    linesWidths.push(accumWidth);
                    line = ch;
                    accumWidth = chWidth;
                }
            }
            continue;
        }
        accumWidth += chWidth;
        if (inWord) {
            currentWord += ch;
            currentWordWidth += chWidth;
        }
        else {
            if (currentWord) {
                line += currentWord;
                currentWord = '';
                currentWordWidth = 0;
            }
            line += ch;
        }
    }
    if (!lines.length && !line) {
        line = text;
        currentWord = '';
        currentWordWidth = 0;
    }
    if (currentWord) {
        line += currentWord;
    }
    if (line) {
        lines.push(line);
        linesWidths.push(accumWidth);
    }
    if (lines.length === 1) {
        accumWidth += lastAccumWidth;
    }
    return {
        accumWidth: accumWidth,
        lines: lines,
        linesWidths: linesWidths
    };
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/vector.js
function vector_create(x, y) {
    if (x == null) {
        x = 0;
    }
    if (y == null) {
        y = 0;
    }
    return [x, y];
}
function vector_copy(out, v) {
    out[0] = v[0];
    out[1] = v[1];
    return out;
}
function vector_clone(v) {
    return [v[0], v[1]];
}
function set(out, a, b) {
    out[0] = a;
    out[1] = b;
    return out;
}
function add(out, v1, v2) {
    out[0] = v1[0] + v2[0];
    out[1] = v1[1] + v2[1];
    return out;
}
function scaleAndAdd(out, v1, v2, a) {
    out[0] = v1[0] + v2[0] * a;
    out[1] = v1[1] + v2[1] * a;
    return out;
}
function sub(out, v1, v2) {
    out[0] = v1[0] - v2[0];
    out[1] = v1[1] - v2[1];
    return out;
}
function len(v) {
    return Math.sqrt(lenSquare(v));
}
var vector_length = len;
function lenSquare(v) {
    return v[0] * v[0] + v[1] * v[1];
}
var lengthSquare = lenSquare;
function vector_mul(out, v1, v2) {
    out[0] = v1[0] * v2[0];
    out[1] = v1[1] * v2[1];
    return out;
}
function div(out, v1, v2) {
    out[0] = v1[0] / v2[0];
    out[1] = v1[1] / v2[1];
    return out;
}
function dot(v1, v2) {
    return v1[0] * v2[0] + v1[1] * v2[1];
}
function vector_scale(out, v, s) {
    out[0] = v[0] * s;
    out[1] = v[1] * s;
    return out;
}
function normalize(out, v) {
    var d = len(v);
    if (d === 0) {
        out[0] = 0;
        out[1] = 0;
    }
    else {
        out[0] = v[0] / d;
        out[1] = v[1] / d;
    }
    return out;
}
function vector_distance(v1, v2) {
    return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0])
        + (v1[1] - v2[1]) * (v1[1] - v2[1]));
}
var dist = vector_distance;
function distanceSquare(v1, v2) {
    return (v1[0] - v2[0]) * (v1[0] - v2[0])
        + (v1[1] - v2[1]) * (v1[1] - v2[1]);
}
var distSquare = distanceSquare;
function negate(out, v) {
    out[0] = -v[0];
    out[1] = -v[1];
    return out;
}
function vector_lerp(out, v1, v2, t) {
    out[0] = v1[0] + t * (v2[0] - v1[0]);
    out[1] = v1[1] + t * (v2[1] - v1[1]);
    return out;
}
function applyTransform(out, v, m) {
    var x = v[0];
    var y = v[1];
    out[0] = m[0] * x + m[2] * y + m[4];
    out[1] = m[1] * x + m[3] * y + m[5];
    return out;
}
function vector_min(out, v1, v2) {
    out[0] = Math.min(v1[0], v2[0]);
    out[1] = Math.min(v1[1], v2[1]);
    return out;
}
function vector_max(out, v1, v2) {
    out[0] = Math.max(v1[0], v2[0]);
    out[1] = Math.max(v1[1], v2[1]);
    return out;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/Transformable.js


var mIdentity = identity;
var Transformable_EPSILON = 5e-5;
function isNotAroundZero(val) {
    return val > Transformable_EPSILON || val < -Transformable_EPSILON;
}
var scaleTmp = [];
var tmpTransform = [];
var originTransform = create();
var Transformable_abs = Math.abs;
var Transformable = (function () {
    function Transformable() {
    }
    Transformable.prototype.setPosition = function (arr) {
        this.x = arr[0];
        this.y = arr[1];
    };
    Transformable.prototype.setScale = function (arr) {
        this.scaleX = arr[0];
        this.scaleY = arr[1];
    };
    Transformable.prototype.setSkew = function (arr) {
        this.skewX = arr[0];
        this.skewY = arr[1];
    };
    Transformable.prototype.setOrigin = function (arr) {
        this.originX = arr[0];
        this.originY = arr[1];
    };
    Transformable.prototype.needLocalTransform = function () {
        return isNotAroundZero(this.rotation)
            || isNotAroundZero(this.x)
            || isNotAroundZero(this.y)
            || isNotAroundZero(this.scaleX - 1)
            || isNotAroundZero(this.scaleY - 1);
    };
    Transformable.prototype.updateTransform = function () {
        var parent = this.parent;
        var parentHasTransform = parent && parent.transform;
        var needLocalTransform = this.needLocalTransform();
        var m = this.transform;
        if (!(needLocalTransform || parentHasTransform)) {
            m && mIdentity(m);
            return;
        }
        m = m || create();
        if (needLocalTransform) {
            this.getLocalTransform(m);
        }
        else {
            mIdentity(m);
        }
        if (parentHasTransform) {
            if (needLocalTransform) {
                mul(m, parent.transform, m);
            }
            else {
                copy(m, parent.transform);
            }
        }
        this.transform = m;
        this._resolveGlobalScaleRatio(m);
    };
    Transformable.prototype._resolveGlobalScaleRatio = function (m) {
        var globalScaleRatio = this.globalScaleRatio;
        if (globalScaleRatio != null && globalScaleRatio !== 1) {
            this.getGlobalScale(scaleTmp);
            var relX = scaleTmp[0] < 0 ? -1 : 1;
            var relY = scaleTmp[1] < 0 ? -1 : 1;
            var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;
            var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;
            m[0] *= sx;
            m[1] *= sx;
            m[2] *= sy;
            m[3] *= sy;
        }
        this.invTransform = this.invTransform || create();
        matrix_invert(this.invTransform, m);
    };
    Transformable.prototype.getLocalTransform = function (m) {
        return Transformable.getLocalTransform(this, m);
    };
    Transformable.prototype.getComputedTransform = function () {
        var transformNode = this;
        var ancestors = [];
        while (transformNode) {
            ancestors.push(transformNode);
            transformNode = transformNode.parent;
        }
        while (transformNode = ancestors.pop()) {
            transformNode.updateTransform();
        }
        return this.transform;
    };
    Transformable.prototype.setLocalTransform = function (m) {
        if (!m) {
            return;
        }
        var sx = m[0] * m[0] + m[1] * m[1];
        var sy = m[2] * m[2] + m[3] * m[3];
        var rotation = Math.atan2(m[1], m[0]);
        var shearX = Math.PI / 2 + rotation - Math.atan2(m[3], m[2]);
        sy = Math.sqrt(sy) * Math.cos(shearX);
        sx = Math.sqrt(sx);
        this.skewX = shearX;
        this.skewY = 0;
        this.rotation = -rotation;
        this.x = +m[4];
        this.y = +m[5];
        this.scaleX = sx;
        this.scaleY = sy;
        this.originX = 0;
        this.originY = 0;
    };
    Transformable.prototype.decomposeTransform = function () {
        if (!this.transform) {
            return;
        }
        var parent = this.parent;
        var m = this.transform;
        if (parent && parent.transform) {
            mul(tmpTransform, parent.invTransform, m);
            m = tmpTransform;
        }
        var ox = this.originX;
        var oy = this.originY;
        if (ox || oy) {
            originTransform[4] = ox;
            originTransform[5] = oy;
            mul(tmpTransform, m, originTransform);
            tmpTransform[4] -= ox;
            tmpTransform[5] -= oy;
            m = tmpTransform;
        }
        this.setLocalTransform(m);
    };
    Transformable.prototype.getGlobalScale = function (out) {
        var m = this.transform;
        out = out || [];
        if (!m) {
            out[0] = 1;
            out[1] = 1;
            return out;
        }
        out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
        out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);
        if (m[0] < 0) {
            out[0] = -out[0];
        }
        if (m[3] < 0) {
            out[1] = -out[1];
        }
        return out;
    };
    Transformable.prototype.transformCoordToLocal = function (x, y) {
        var v2 = [x, y];
        var invTransform = this.invTransform;
        if (invTransform) {
            applyTransform(v2, v2, invTransform);
        }
        return v2;
    };
    Transformable.prototype.transformCoordToGlobal = function (x, y) {
        var v2 = [x, y];
        var transform = this.transform;
        if (transform) {
            applyTransform(v2, v2, transform);
        }
        return v2;
    };
    Transformable.prototype.getLineScale = function () {
        var m = this.transform;
        return m && Transformable_abs(m[0] - 1) > 1e-10 && Transformable_abs(m[3] - 1) > 1e-10
            ? Math.sqrt(Transformable_abs(m[0] * m[3] - m[2] * m[1]))
            : 1;
    };
    Transformable.getLocalTransform = function (target, m) {
        m = m || [];
        var ox = target.originX || 0;
        var oy = target.originY || 0;
        var sx = target.scaleX;
        var sy = target.scaleY;
        var rotation = target.rotation || 0;
        var x = target.x;
        var y = target.y;
        var skewX = target.skewX ? Math.tan(target.skewX) : 0;
        var skewY = target.skewY ? Math.tan(-target.skewY) : 0;
        if (ox || oy) {
            m[4] = -ox * sx - skewX * oy * sy;
            m[5] = -oy * sy - skewY * ox * sx;
        }
        else {
            m[4] = m[5] = 0;
        }
        m[0] = sx;
        m[3] = sy;
        m[1] = skewY * sx;
        m[2] = skewX * sy;
        rotation && rotate(m, m, rotation);
        m[4] += ox + x;
        m[5] += oy + y;
        return m;
    };
    Transformable.initDefaultProps = (function () {
        var proto = Transformable.prototype;
        proto.x = 0;
        proto.y = 0;
        proto.scaleX = 1;
        proto.scaleY = 1;
        proto.originX = 0;
        proto.originY = 0;
        proto.skewX = 0;
        proto.skewY = 0;
        proto.rotation = 0;
        proto.globalScaleRatio = 1;
    })();
    return Transformable;
}());
;
/* harmony default export */ const core_Transformable = (Transformable);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/Eventful.js
var Eventful = (function () {
    function Eventful(eventProcessors) {
        if (eventProcessors) {
            this._$eventProcessor = eventProcessors;
        }
    }
    Eventful.prototype.on = function (event, query, handler, context) {
        if (!this._$handlers) {
            this._$handlers = {};
        }
        var _h = this._$handlers;
        if (typeof query === 'function') {
            context = handler;
            handler = query;
            query = null;
        }
        if (!handler || !event) {
            return this;
        }
        var eventProcessor = this._$eventProcessor;
        if (query != null && eventProcessor && eventProcessor.normalizeQuery) {
            query = eventProcessor.normalizeQuery(query);
        }
        if (!_h[event]) {
            _h[event] = [];
        }
        for (var i = 0; i < _h[event].length; i++) {
            if (_h[event][i].h === handler) {
                return this;
            }
        }
        var wrap = {
            h: handler,
            query: query,
            ctx: (context || this),
            callAtLast: handler.zrEventfulCallAtLast
        };
        var lastIndex = _h[event].length - 1;
        var lastWrap = _h[event][lastIndex];
        (lastWrap && lastWrap.callAtLast)
            ? _h[event].splice(lastIndex, 0, wrap)
            : _h[event].push(wrap);
        return this;
    };
    Eventful.prototype.isSilent = function (eventName) {
        var _h = this._$handlers;
        return !_h || !_h[eventName] || !_h[eventName].length;
    };
    Eventful.prototype.off = function (eventType, handler) {
        var _h = this._$handlers;
        if (!_h) {
            return this;
        }
        if (!eventType) {
            this._$handlers = {};
            return this;
        }
        if (handler) {
            if (_h[eventType]) {
                var newList = [];
                for (var i = 0, l = _h[eventType].length; i < l; i++) {
                    if (_h[eventType][i].h !== handler) {
                        newList.push(_h[eventType][i]);
                    }
                }
                _h[eventType] = newList;
            }
            if (_h[eventType] && _h[eventType].length === 0) {
                delete _h[eventType];
            }
        }
        else {
            delete _h[eventType];
        }
        return this;
    };
    Eventful.prototype.trigger = function (eventType) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        if (!this._$handlers) {
            return this;
        }
        var _h = this._$handlers[eventType];
        var eventProcessor = this._$eventProcessor;
        if (_h) {
            var argLen = args.length;
            var len = _h.length;
            for (var i = 0; i < len; i++) {
                var hItem = _h[i];
                if (eventProcessor
                    && eventProcessor.filter
                    && hItem.query != null
                    && !eventProcessor.filter(eventType, hItem.query)) {
                    continue;
                }
                switch (argLen) {
                    case 0:
                        hItem.h.call(hItem.ctx);
                        break;
                    case 1:
                        hItem.h.call(hItem.ctx, args[0]);
                        break;
                    case 2:
                        hItem.h.call(hItem.ctx, args[0], args[1]);
                        break;
                    default:
                        hItem.h.apply(hItem.ctx, args);
                        break;
                }
            }
        }
        eventProcessor && eventProcessor.afterTrigger
            && eventProcessor.afterTrigger(eventType);
        return this;
    };
    Eventful.prototype.triggerWithContext = function (type) {
        if (!this._$handlers) {
            return this;
        }
        var _h = this._$handlers[type];
        var eventProcessor = this._$eventProcessor;
        if (_h) {
            var args = arguments;
            var argLen = args.length;
            var ctx = args[argLen - 1];
            var len = _h.length;
            for (var i = 0; i < len; i++) {
                var hItem = _h[i];
                if (eventProcessor
                    && eventProcessor.filter
                    && hItem.query != null
                    && !eventProcessor.filter(type, hItem.query)) {
                    continue;
                }
                switch (argLen) {
                    case 0:
                        hItem.h.call(ctx);
                        break;
                    case 1:
                        hItem.h.call(ctx, args[0]);
                        break;
                    case 2:
                        hItem.h.call(ctx, args[0], args[1]);
                        break;
                    default:
                        hItem.h.apply(ctx, args.slice(1, argLen - 1));
                        break;
                }
            }
        }
        eventProcessor && eventProcessor.afterTrigger
            && eventProcessor.afterTrigger(type);
        return this;
    };
    return Eventful;
}());
/* harmony default export */ const core_Eventful = (Eventful);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/config.js
var dpr = 1;
if (typeof window !== 'undefined') {
    dpr = Math.max(window.devicePixelRatio
        || (window.screen && window.screen.deviceXDPI / window.screen.logicalXDPI)
        || 1, 1);
}
var debugMode = 0;
var devicePixelRatio = dpr;
var DARK_MODE_THRESHOLD = 0.4;
var DARK_LABEL_COLOR = '#333';
var LIGHT_LABEL_COLOR = '#ccc';
var LIGHTER_LABEL_COLOR = '#eee';

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/env.js
var Browser = (function () {
    function Browser() {
        this.firefox = false;
        this.ie = false;
        this.edge = false;
        this.newEdge = false;
        this.weChat = false;
    }
    return Browser;
}());
var Env = (function () {
    function Env() {
        this.browser = new Browser();
        this.node = false;
        this.wxa = false;
        this.worker = false;
        this.canvasSupported = false;
        this.svgSupported = false;
        this.touchEventsSupported = false;
        this.pointerEventsSupported = false;
        this.domSupported = false;
        this.transformSupported = false;
        this.transform3dSupported = false;
    }
    return Env;
}());
var env = new Env();
if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {
    env.wxa = true;
    env.canvasSupported = true;
    env.touchEventsSupported = true;
}
else if (typeof document === 'undefined' && typeof self !== 'undefined') {
    env.worker = true;
    env.canvasSupported = true;
}
else if (typeof navigator === 'undefined') {
    env.node = true;
    env.canvasSupported = true;
    env.svgSupported = true;
}
else {
    detect(navigator.userAgent, env);
}
function detect(ua, env) {
    var browser = env.browser;
    var firefox = ua.match(/Firefox\/([\d.]+)/);
    var ie = ua.match(/MSIE\s([\d.]+)/)
        || ua.match(/Trident\/.+?rv:(([\d.]+))/);
    var edge = ua.match(/Edge?\/([\d.]+)/);
    var weChat = (/micromessenger/i).test(ua);
    if (firefox) {
        browser.firefox = true;
        browser.version = firefox[1];
    }
    if (ie) {
        browser.ie = true;
        browser.version = ie[1];
    }
    if (edge) {
        browser.edge = true;
        browser.version = edge[1];
        browser.newEdge = +edge[1].split('.')[0] > 18;
    }
    if (weChat) {
        browser.weChat = true;
    }
    env.canvasSupported = !!document.createElement('canvas').getContext;
    env.svgSupported = typeof SVGRect !== 'undefined';
    env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge;
    env.pointerEventsSupported = 'onpointerdown' in window
        && (browser.edge || (browser.ie && +browser.version >= 11));
    env.domSupported = typeof document !== 'undefined';
    var style = document.documentElement.style;
    env.transform3dSupported = ((browser.ie && 'transition' in style)
        || browser.edge
        || (('WebKitCSSMatrix' in window) && ('m11' in new WebKitCSSMatrix()))
        || 'MozPerspective' in style)
        && !('OTransition' in style);
    env.transformSupported = env.transform3dSupported
        || (browser.ie && +browser.version >= 9);
}
/* harmony default export */ const core_env = (env);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/constants.js
var REDARAW_BIT = 1;
var STYLE_CHANGED_BIT = 2;
var SHAPE_CHANGED_BIT = 4;

;// CONCATENATED MODULE: ./node_modules/zrender/lib/Element.js










var PRESERVED_NORMAL_STATE = '__zr_normal__';
var PRIMARY_STATES_KEYS = ['x', 'y', 'scaleX', 'scaleY', 'originX', 'originY', 'rotation', 'ignore'];
var DEFAULT_ANIMATABLE_MAP = {
    x: true,
    y: true,
    scaleX: true,
    scaleY: true,
    originX: true,
    originY: true,
    rotation: true,
    ignore: false
};
var tmpTextPosCalcRes = {};
var tmpBoundingRect = new core_BoundingRect(0, 0, 0, 0);
var Element = (function () {
    function Element(props) {
        this.id = util_guid();
        this.animators = [];
        this.currentStates = [];
        this.states = {};
        this._init(props);
    }
    Element.prototype._init = function (props) {
        this.attr(props);
    };
    Element.prototype.drift = function (dx, dy, e) {
        switch (this.draggable) {
            case 'horizontal':
                dy = 0;
                break;
            case 'vertical':
                dx = 0;
                break;
        }
        var m = this.transform;
        if (!m) {
            m = this.transform = [1, 0, 0, 1, 0, 0];
        }
        m[4] += dx;
        m[5] += dy;
        this.decomposeTransform();
        this.markRedraw();
    };
    Element.prototype.beforeUpdate = function () { };
    Element.prototype.afterUpdate = function () { };
    Element.prototype.update = function () {
        this.updateTransform();
        if (this.__dirty) {
            this.updateInnerText();
        }
    };
    Element.prototype.updateInnerText = function (forceUpdate) {
        var textEl = this._textContent;
        if (textEl && (!textEl.ignore || forceUpdate)) {
            if (!this.textConfig) {
                this.textConfig = {};
            }
            var textConfig = this.textConfig;
            var isLocal = textConfig.local;
            var attachedTransform = textEl.attachedTransform;
            var textAlign = void 0;
            var textVerticalAlign = void 0;
            var textStyleChanged = false;
            if (isLocal) {
                attachedTransform.parent = this;
            }
            else {
                attachedTransform.parent = null;
            }
            var innerOrigin = false;
            attachedTransform.x = textEl.x;
            attachedTransform.y = textEl.y;
            attachedTransform.originX = textEl.originX;
            attachedTransform.originY = textEl.originY;
            attachedTransform.rotation = textEl.rotation;
            attachedTransform.scaleX = textEl.scaleX;
            attachedTransform.scaleY = textEl.scaleY;
            if (textConfig.position != null) {
                var layoutRect = tmpBoundingRect;
                if (textConfig.layoutRect) {
                    layoutRect.copy(textConfig.layoutRect);
                }
                else {
                    layoutRect.copy(this.getBoundingRect());
                }
                if (!isLocal) {
                    layoutRect.applyTransform(this.transform);
                }
                if (this.calculateTextPosition) {
                    this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
                }
                else {
                    calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
                }
                attachedTransform.x = tmpTextPosCalcRes.x;
                attachedTransform.y = tmpTextPosCalcRes.y;
                textAlign = tmpTextPosCalcRes.align;
                textVerticalAlign = tmpTextPosCalcRes.verticalAlign;
                var textOrigin = textConfig.origin;
                if (textOrigin && textConfig.rotation != null) {
                    var relOriginX = void 0;
                    var relOriginY = void 0;
                    if (textOrigin === 'center') {
                        relOriginX = layoutRect.width * 0.5;
                        relOriginY = layoutRect.height * 0.5;
                    }
                    else {
                        relOriginX = parsePercent(textOrigin[0], layoutRect.width);
                        relOriginY = parsePercent(textOrigin[1], layoutRect.height);
                    }
                    innerOrigin = true;
                    attachedTransform.originX = -attachedTransform.x + relOriginX + (isLocal ? 0 : layoutRect.x);
                    attachedTransform.originY = -attachedTransform.y + relOriginY + (isLocal ? 0 : layoutRect.y);
                }
            }
            if (textConfig.rotation != null) {
                attachedTransform.rotation = textConfig.rotation;
            }
            var textOffset = textConfig.offset;
            if (textOffset) {
                attachedTransform.x += textOffset[0];
                attachedTransform.y += textOffset[1];
                if (!innerOrigin) {
                    attachedTransform.originX = -textOffset[0];
                    attachedTransform.originY = -textOffset[1];
                }
            }
            var isInside = textConfig.inside == null
                ? (typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0)
                : textConfig.inside;
            var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
            var textFill = void 0;
            var textStroke = void 0;
            var autoStroke = void 0;
            if (isInside && this.canBeInsideText()) {
                textFill = textConfig.insideFill;
                textStroke = textConfig.insideStroke;
                if (textFill == null || textFill === 'auto') {
                    textFill = this.getInsideTextFill();
                }
                if (textStroke == null || textStroke === 'auto') {
                    textStroke = this.getInsideTextStroke(textFill);
                    autoStroke = true;
                }
            }
            else {
                textFill = textConfig.outsideFill;
                textStroke = textConfig.outsideStroke;
                if (textFill == null || textFill === 'auto') {
                    textFill = this.getOutsideFill();
                }
                if (textStroke == null || textStroke === 'auto') {
                    textStroke = this.getOutsideStroke(textFill);
                    autoStroke = true;
                }
            }
            textFill = textFill || '#000';
            if (textFill !== innerTextDefaultStyle.fill
                || textStroke !== innerTextDefaultStyle.stroke
                || autoStroke !== innerTextDefaultStyle.autoStroke
                || textAlign !== innerTextDefaultStyle.align
                || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) {
                textStyleChanged = true;
                innerTextDefaultStyle.fill = textFill;
                innerTextDefaultStyle.stroke = textStroke;
                innerTextDefaultStyle.autoStroke = autoStroke;
                innerTextDefaultStyle.align = textAlign;
                innerTextDefaultStyle.verticalAlign = textVerticalAlign;
                textEl.setDefaultTextStyle(innerTextDefaultStyle);
            }
            textEl.__dirty |= REDARAW_BIT;
            if (textStyleChanged) {
                textEl.dirtyStyle(true);
            }
        }
    };
    Element.prototype.canBeInsideText = function () {
        return true;
    };
    Element.prototype.getInsideTextFill = function () {
        return '#fff';
    };
    Element.prototype.getInsideTextStroke = function (textFill) {
        return '#000';
    };
    Element.prototype.getOutsideFill = function () {
        return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
    };
    Element.prototype.getOutsideStroke = function (textFill) {
        var backgroundColor = this.__zr && this.__zr.getBackgroundColor();
        var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);
        if (!colorArr) {
            colorArr = [255, 255, 255, 1];
        }
        var alpha = colorArr[3];
        var isDark = this.__zr.isDarkMode();
        for (var i = 0; i < 3; i++) {
            colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha);
        }
        colorArr[3] = 1;
        return stringify(colorArr, 'rgba');
    };
    Element.prototype.traverse = function (cb, context) { };
    Element.prototype.attrKV = function (key, value) {
        if (key === 'textConfig') {
            this.setTextConfig(value);
        }
        else if (key === 'textContent') {
            this.setTextContent(value);
        }
        else if (key === 'clipPath') {
            this.setClipPath(value);
        }
        else if (key === 'extra') {
            this.extra = this.extra || {};
            util_extend(this.extra, value);
        }
        else {
            this[key] = value;
        }
    };
    Element.prototype.hide = function () {
        this.ignore = true;
        this.markRedraw();
    };
    Element.prototype.show = function () {
        this.ignore = false;
        this.markRedraw();
    };
    Element.prototype.attr = function (keyOrObj, value) {
        if (typeof keyOrObj === 'string') {
            this.attrKV(keyOrObj, value);
        }
        else if (isObject(keyOrObj)) {
            var obj = keyOrObj;
            var keysArr = keys(obj);
            for (var i = 0; i < keysArr.length; i++) {
                var key = keysArr[i];
                this.attrKV(key, keyOrObj[key]);
            }
        }
        this.markRedraw();
        return this;
    };
    Element.prototype.saveCurrentToNormalState = function (toState) {
        this._innerSaveToNormal(toState);
        var normalState = this._normalState;
        for (var i = 0; i < this.animators.length; i++) {
            var animator = this.animators[i];
            var fromStateTransition = animator.__fromStateTransition;
            if (fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
                continue;
            }
            var targetName = animator.targetName;
            var target = targetName
                ? normalState[targetName] : normalState;
            animator.saveFinalToTarget(target);
        }
    };
    Element.prototype._innerSaveToNormal = function (toState) {
        var normalState = this._normalState;
        if (!normalState) {
            normalState = this._normalState = {};
        }
        if (toState.textConfig && !normalState.textConfig) {
            normalState.textConfig = this.textConfig;
        }
        this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
    };
    Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
        for (var i = 0; i < primaryKeys.length; i++) {
            var key = primaryKeys[i];
            if (toState[key] != null && !(key in normalState)) {
                normalState[key] = this[key];
            }
        }
    };
    Element.prototype.hasState = function () {
        return this.currentStates.length > 0;
    };
    Element.prototype.getState = function (name) {
        return this.states[name];
    };
    Element.prototype.ensureState = function (name) {
        var states = this.states;
        if (!states[name]) {
            states[name] = {};
        }
        return states[name];
    };
    Element.prototype.clearStates = function (noAnimation) {
        this.useState(PRESERVED_NORMAL_STATE, false, noAnimation);
    };
    Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) {
        var toNormalState = stateName === PRESERVED_NORMAL_STATE;
        var hasStates = this.hasState();
        if (!hasStates && toNormalState) {
            return;
        }
        var currentStates = this.currentStates;
        var animationCfg = this.stateTransition;
        if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
            return;
        }
        var state;
        if (this.stateProxy && !toNormalState) {
            state = this.stateProxy(stateName);
        }
        if (!state) {
            state = (this.states && this.states[stateName]);
        }
        if (!state && !toNormalState) {
            logError("State " + stateName + " not exists.");
            return;
        }
        if (!toNormalState) {
            this.saveCurrentToNormalState(state);
        }
        var useHoverLayer = !!((state && state.hoverLayer) || forceUseHoverLayer);
        if (useHoverLayer) {
            this._toggleHoverLayerFlag(true);
        }
        this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
        var textContent = this._textContent;
        var textGuide = this._textGuide;
        if (textContent) {
            textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
        }
        if (textGuide) {
            textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
        }
        if (toNormalState) {
            this.currentStates = [];
            this._normalState = {};
        }
        else {
            if (!keepCurrentStates) {
                this.currentStates = [stateName];
            }
            else {
                this.currentStates.push(stateName);
            }
        }
        this._updateAnimationTargets();
        this.markRedraw();
        if (!useHoverLayer && this.__inHover) {
            this._toggleHoverLayerFlag(false);
            this.__dirty &= ~REDARAW_BIT;
        }
        return state;
    };
    Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) {
        if (!states.length) {
            this.clearStates();
        }
        else {
            var stateObjects = [];
            var currentStates = this.currentStates;
            var len = states.length;
            var notChange = len === currentStates.length;
            if (notChange) {
                for (var i = 0; i < len; i++) {
                    if (states[i] !== currentStates[i]) {
                        notChange = false;
                        break;
                    }
                }
            }
            if (notChange) {
                return;
            }
            for (var i = 0; i < len; i++) {
                var stateName = states[i];
                var stateObj = void 0;
                if (this.stateProxy) {
                    stateObj = this.stateProxy(stateName, states);
                }
                if (!stateObj) {
                    stateObj = this.states[stateName];
                }
                if (stateObj) {
                    stateObjects.push(stateObj);
                }
            }
            var lastStateObj = stateObjects[len - 1];
            var useHoverLayer = !!((lastStateObj && lastStateObj.hoverLayer) || forceUseHoverLayer);
            if (useHoverLayer) {
                this._toggleHoverLayerFlag(true);
            }
            var mergedState = this._mergeStates(stateObjects);
            var animationCfg = this.stateTransition;
            this.saveCurrentToNormalState(mergedState);
            this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
            var textContent = this._textContent;
            var textGuide = this._textGuide;
            if (textContent) {
                textContent.useStates(states, noAnimation, useHoverLayer);
            }
            if (textGuide) {
                textGuide.useStates(states, noAnimation, useHoverLayer);
            }
            this._updateAnimationTargets();
            this.currentStates = states.slice();
            this.markRedraw();
            if (!useHoverLayer && this.__inHover) {
                this._toggleHoverLayerFlag(false);
                this.__dirty &= ~REDARAW_BIT;
            }
        }
    };
    Element.prototype._updateAnimationTargets = function () {
        for (var i = 0; i < this.animators.length; i++) {
            var animator = this.animators[i];
            if (animator.targetName) {
                animator.changeTarget(this[animator.targetName]);
            }
        }
    };
    Element.prototype.removeState = function (state) {
        var idx = indexOf(this.currentStates, state);
        if (idx >= 0) {
            var currentStates = this.currentStates.slice();
            currentStates.splice(idx, 1);
            this.useStates(currentStates);
        }
    };
    Element.prototype.replaceState = function (oldState, newState, forceAdd) {
        var currentStates = this.currentStates.slice();
        var idx = indexOf(currentStates, oldState);
        var newStateExists = indexOf(currentStates, newState) >= 0;
        if (idx >= 0) {
            if (!newStateExists) {
                currentStates[idx] = newState;
            }
            else {
                currentStates.splice(idx, 1);
            }
        }
        else if (forceAdd && !newStateExists) {
            currentStates.push(newState);
        }
        this.useStates(currentStates);
    };
    Element.prototype.toggleState = function (state, enable) {
        if (enable) {
            this.useState(state, true);
        }
        else {
            this.removeState(state);
        }
    };
    Element.prototype._mergeStates = function (states) {
        var mergedState = {};
        var mergedTextConfig;
        for (var i = 0; i < states.length; i++) {
            var state = states[i];
            util_extend(mergedState, state);
            if (state.textConfig) {
                mergedTextConfig = mergedTextConfig || {};
                util_extend(mergedTextConfig, state.textConfig);
            }
        }
        if (mergedTextConfig) {
            mergedState.textConfig = mergedTextConfig;
        }
        return mergedState;
    };
    Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
        var needsRestoreToNormal = !(state && keepCurrentStates);
        if (state && state.textConfig) {
            this.textConfig = util_extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig);
            util_extend(this.textConfig, state.textConfig);
        }
        else if (needsRestoreToNormal) {
            if (normalState.textConfig) {
                this.textConfig = normalState.textConfig;
            }
        }
        var transitionTarget = {};
        var hasTransition = false;
        for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
            var key = PRIMARY_STATES_KEYS[i];
            var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];
            if (state && state[key] != null) {
                if (propNeedsTransition) {
                    hasTransition = true;
                    transitionTarget[key] = state[key];
                }
                else {
                    this[key] = state[key];
                }
            }
            else if (needsRestoreToNormal) {
                if (normalState[key] != null) {
                    if (propNeedsTransition) {
                        hasTransition = true;
                        transitionTarget[key] = normalState[key];
                    }
                    else {
                        this[key] = normalState[key];
                    }
                }
            }
        }
        if (!transition) {
            for (var i = 0; i < this.animators.length; i++) {
                var animator = this.animators[i];
                var targetName = animator.targetName;
                animator.__changeFinalValue(targetName
                    ? (state || normalState)[targetName]
                    : (state || normalState));
            }
        }
        if (hasTransition) {
            this._transitionState(stateName, transitionTarget, animationCfg);
        }
    };
    Element.prototype._attachComponent = function (componentEl) {
        if (componentEl.__zr && !componentEl.__hostTarget) {
            throw new Error('Text element has been added to zrender.');
        }
        if (componentEl === this) {
            throw new Error('Recursive component attachment.');
        }
        var zr = this.__zr;
        if (zr) {
            componentEl.addSelfToZr(zr);
        }
        componentEl.__zr = zr;
        componentEl.__hostTarget = this;
    };
    Element.prototype._detachComponent = function (componentEl) {
        if (componentEl.__zr) {
            componentEl.removeSelfFromZr(componentEl.__zr);
        }
        componentEl.__zr = null;
        componentEl.__hostTarget = null;
    };
    Element.prototype.getClipPath = function () {
        return this._clipPath;
    };
    Element.prototype.setClipPath = function (clipPath) {
        if (this._clipPath && this._clipPath !== clipPath) {
            this.removeClipPath();
        }
        this._attachComponent(clipPath);
        this._clipPath = clipPath;
        this.markRedraw();
    };
    Element.prototype.removeClipPath = function () {
        var clipPath = this._clipPath;
        if (clipPath) {
            this._detachComponent(clipPath);
            this._clipPath = null;
            this.markRedraw();
        }
    };
    Element.prototype.getTextContent = function () {
        return this._textContent;
    };
    Element.prototype.setTextContent = function (textEl) {
        var previousTextContent = this._textContent;
        if (previousTextContent === textEl) {
            return;
        }
        if (previousTextContent && previousTextContent !== textEl) {
            this.removeTextContent();
        }
        if (textEl.__zr && !textEl.__hostTarget) {
            throw new Error('Text element has been added to zrender.');
        }
        textEl.attachedTransform = new core_Transformable();
        this._attachComponent(textEl);
        this._textContent = textEl;
        this.markRedraw();
    };
    Element.prototype.setTextConfig = function (cfg) {
        if (!this.textConfig) {
            this.textConfig = {};
        }
        util_extend(this.textConfig, cfg);
        this.markRedraw();
    };
    Element.prototype.removeTextConfig = function () {
        this.textConfig = null;
        this.markRedraw();
    };
    Element.prototype.removeTextContent = function () {
        var textEl = this._textContent;
        if (textEl) {
            textEl.attachedTransform = null;
            this._detachComponent(textEl);
            this._textContent = null;
            this._innerTextDefaultStyle = null;
            this.markRedraw();
        }
    };
    Element.prototype.getTextGuideLine = function () {
        return this._textGuide;
    };
    Element.prototype.setTextGuideLine = function (guideLine) {
        if (this._textGuide && this._textGuide !== guideLine) {
            this.removeTextGuideLine();
        }
        this._attachComponent(guideLine);
        this._textGuide = guideLine;
        this.markRedraw();
    };
    Element.prototype.removeTextGuideLine = function () {
        var textGuide = this._textGuide;
        if (textGuide) {
            this._detachComponent(textGuide);
            this._textGuide = null;
            this.markRedraw();
        }
    };
    Element.prototype.markRedraw = function () {
        this.__dirty |= REDARAW_BIT;
        var zr = this.__zr;
        if (zr) {
            if (this.__inHover) {
                zr.refreshHover();
            }
            else {
                zr.refresh();
            }
        }
        if (this.__hostTarget) {
            this.__hostTarget.markRedraw();
        }
    };
    Element.prototype.dirty = function () {
        this.markRedraw();
    };
    Element.prototype._toggleHoverLayerFlag = function (inHover) {
        this.__inHover = inHover;
        var textContent = this._textContent;
        var textGuide = this._textGuide;
        if (textContent) {
            textContent.__inHover = inHover;
        }
        if (textGuide) {
            textGuide.__inHover = inHover;
        }
    };
    Element.prototype.addSelfToZr = function (zr) {
        this.__zr = zr;
        var animators = this.animators;
        if (animators) {
            for (var i = 0; i < animators.length; i++) {
                zr.animation.addAnimator(animators[i]);
            }
        }
        if (this._clipPath) {
            this._clipPath.addSelfToZr(zr);
        }
        if (this._textContent) {
            this._textContent.addSelfToZr(zr);
        }
        if (this._textGuide) {
            this._textGuide.addSelfToZr(zr);
        }
    };
    Element.prototype.removeSelfFromZr = function (zr) {
        this.__zr = null;
        var animators = this.animators;
        if (animators) {
            for (var i = 0; i < animators.length; i++) {
                zr.animation.removeAnimator(animators[i]);
            }
        }
        if (this._clipPath) {
            this._clipPath.removeSelfFromZr(zr);
        }
        if (this._textContent) {
            this._textContent.removeSelfFromZr(zr);
        }
        if (this._textGuide) {
            this._textGuide.removeSelfFromZr(zr);
        }
    };
    Element.prototype.animate = function (key, loop) {
        var target = key ? this[key] : this;
        if (!target) {
            logError('Property "'
                + key
                + '" is not existed in element '
                + this.id);
            return;
        }
        var animator = new animation_Animator(target, loop);
        this.addAnimator(animator, key);
        return animator;
    };
    Element.prototype.addAnimator = function (animator, key) {
        var zr = this.__zr;
        var el = this;
        animator.during(function () {
            el.updateDuringAnimation(key);
        }).done(function () {
            var animators = el.animators;
            var idx = indexOf(animators, animator);
            if (idx >= 0) {
                animators.splice(idx, 1);
            }
        });
        this.animators.push(animator);
        if (zr) {
            zr.animation.addAnimator(animator);
        }
        zr && zr.wakeUp();
    };
    Element.prototype.updateDuringAnimation = function (key) {
        this.markRedraw();
    };
    Element.prototype.stopAnimation = function (scope, forwardToLast) {
        var animators = this.animators;
        var len = animators.length;
        var leftAnimators = [];
        for (var i = 0; i < len; i++) {
            var animator = animators[i];
            if (!scope || scope === animator.scope) {
                animator.stop(forwardToLast);
            }
            else {
                leftAnimators.push(animator);
            }
        }
        this.animators = leftAnimators;
        return this;
    };
    Element.prototype.animateTo = function (target, cfg, animationProps) {
        animateTo(this, target, cfg, animationProps);
    };
    Element.prototype.animateFrom = function (target, cfg, animationProps) {
        animateTo(this, target, cfg, animationProps, true);
    };
    Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
        var animators = animateTo(this, target, cfg, animationProps);
        for (var i = 0; i < animators.length; i++) {
            animators[i].__fromStateTransition = stateName;
        }
    };
    Element.prototype.getBoundingRect = function () {
        return null;
    };
    Element.prototype.getPaintRect = function () {
        return null;
    };
    Element.initDefaultProps = (function () {
        var elProto = Element.prototype;
        elProto.type = 'element';
        elProto.name = '';
        elProto.ignore = false;
        elProto.silent = false;
        elProto.isGroup = false;
        elProto.draggable = false;
        elProto.dragging = false;
        elProto.ignoreClip = false;
        elProto.__inHover = false;
        elProto.__dirty = REDARAW_BIT;
        var logs = {};
        function logDeprecatedError(key, xKey, yKey) {
            if (!logs[key + xKey + yKey]) {
                console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead");
                logs[key + xKey + yKey] = true;
            }
        }
        function createLegacyProperty(key, privateKey, xKey, yKey) {
            Object.defineProperty(elProto, key, {
                get: function () {
                    logDeprecatedError(key, xKey, yKey);
                    if (!this[privateKey]) {
                        var pos = this[privateKey] = [];
                        enhanceArray(this, pos);
                    }
                    return this[privateKey];
                },
                set: function (pos) {
                    logDeprecatedError(key, xKey, yKey);
                    this[xKey] = pos[0];
                    this[yKey] = pos[1];
                    this[privateKey] = pos;
                    enhanceArray(this, pos);
                }
            });
            function enhanceArray(self, pos) {
                Object.defineProperty(pos, 0, {
                    get: function () {
                        return self[xKey];
                    },
                    set: function (val) {
                        self[xKey] = val;
                    }
                });
                Object.defineProperty(pos, 1, {
                    get: function () {
                        return self[yKey];
                    },
                    set: function (val) {
                        self[yKey] = val;
                    }
                });
            }
        }
        if (Object.defineProperty && (!core_env.browser.ie || core_env.browser.version > 8)) {
            createLegacyProperty('position', '_legacyPos', 'x', 'y');
            createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
            createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
        }
    })();
    return Element;
}());
mixin(Element, core_Eventful);
mixin(Element, core_Transformable);
function animateTo(animatable, target, cfg, animationProps, reverse) {
    cfg = cfg || {};
    var animators = [];
    animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
    var finishCount = animators.length;
    var doneHappened = false;
    var cfgDone = cfg.done;
    var cfgAborted = cfg.aborted;
    var doneCb = function () {
        doneHappened = true;
        finishCount--;
        if (finishCount <= 0) {
            doneHappened
                ? (cfgDone && cfgDone())
                : (cfgAborted && cfgAborted());
        }
    };
    var abortedCb = function () {
        finishCount--;
        if (finishCount <= 0) {
            doneHappened
                ? (cfgDone && cfgDone())
                : (cfgAborted && cfgAborted());
        }
    };
    if (!finishCount) {
        cfgDone && cfgDone();
    }
    if (animators.length > 0 && cfg.during) {
        animators[0].during(function (target, percent) {
            cfg.during(percent);
        });
    }
    for (var i = 0; i < animators.length; i++) {
        var animator = animators[i];
        if (doneCb) {
            animator.done(doneCb);
        }
        if (abortedCb) {
            animator.aborted(abortedCb);
        }
        animator.start(cfg.easing, cfg.force);
    }
    return animators;
}
function copyArrShallow(source, target, len) {
    for (var i = 0; i < len; i++) {
        source[i] = target[i];
    }
}
function is2DArray(value) {
    return isArrayLike(value[0]);
}
function copyValue(target, source, key) {
    if (isArrayLike(source[key])) {
        if (!isArrayLike(target[key])) {
            target[key] = [];
        }
        if (isTypedArray(source[key])) {
            var len = source[key].length;
            if (target[key].length !== len) {
                target[key] = new (source[key].constructor)(len);
                copyArrShallow(target[key], source[key], len);
            }
        }
        else {
            var sourceArr = source[key];
            var targetArr = target[key];
            var len0 = sourceArr.length;
            if (is2DArray(sourceArr)) {
                var len1 = sourceArr[0].length;
                for (var i = 0; i < len0; i++) {
                    if (!targetArr[i]) {
                        targetArr[i] = Array.prototype.slice.call(sourceArr[i]);
                    }
                    else {
                        copyArrShallow(targetArr[i], sourceArr[i], len1);
                    }
                }
            }
            else {
                copyArrShallow(targetArr, sourceArr, len0);
            }
            targetArr.length = sourceArr.length;
        }
    }
    else {
        target[key] = source[key];
    }
}
function animateToShallow(animatable, topKey, source, target, cfg, animationProps, animators, reverse) {
    var animatableKeys = [];
    var changedKeys = [];
    var targetKeys = keys(target);
    var duration = cfg.duration;
    var delay = cfg.delay;
    var additive = cfg.additive;
    var setToFinal = cfg.setToFinal;
    var animateAll = !isObject(animationProps);
    for (var k = 0; k < targetKeys.length; k++) {
        var innerKey = targetKeys[k];
        if (source[innerKey] != null
            && target[innerKey] != null
            && (animateAll || animationProps[innerKey])) {
            if (isObject(target[innerKey]) && !isArrayLike(target[innerKey])) {
                if (topKey) {
                    if (!reverse) {
                        source[innerKey] = target[innerKey];
                        animatable.updateDuringAnimation(topKey);
                    }
                    continue;
                }
                animateToShallow(animatable, innerKey, source[innerKey], target[innerKey], cfg, animationProps && animationProps[innerKey], animators, reverse);
            }
            else {
                animatableKeys.push(innerKey);
                changedKeys.push(innerKey);
            }
        }
        else if (!reverse) {
            source[innerKey] = target[innerKey];
            animatable.updateDuringAnimation(topKey);
            changedKeys.push(innerKey);
        }
    }
    var keyLen = animatableKeys.length;
    if (keyLen > 0
        || (cfg.force && !animators.length)) {
        var existsAnimators = animatable.animators;
        var existsAnimatorsOnSameTarget = [];
        for (var i = 0; i < existsAnimators.length; i++) {
            if (existsAnimators[i].targetName === topKey) {
                existsAnimatorsOnSameTarget.push(existsAnimators[i]);
            }
        }
        if (!additive && existsAnimatorsOnSameTarget.length) {
            for (var i = 0; i < existsAnimatorsOnSameTarget.length; i++) {
                var allAborted = existsAnimatorsOnSameTarget[i].stopTracks(changedKeys);
                if (allAborted) {
                    var idx = indexOf(existsAnimators, existsAnimatorsOnSameTarget[i]);
                    existsAnimators.splice(idx, 1);
                }
            }
        }
        var revertedSource = void 0;
        var reversedTarget = void 0;
        var sourceClone = void 0;
        if (reverse) {
            reversedTarget = {};
            if (setToFinal) {
                revertedSource = {};
            }
            for (var i = 0; i < keyLen; i++) {
                var innerKey = animatableKeys[i];
                reversedTarget[innerKey] = source[innerKey];
                if (setToFinal) {
                    revertedSource[innerKey] = target[innerKey];
                }
                else {
                    source[innerKey] = target[innerKey];
                }
            }
        }
        else if (setToFinal) {
            sourceClone = {};
            for (var i = 0; i < keyLen; i++) {
                var innerKey = animatableKeys[i];
                sourceClone[innerKey] = cloneValue(source[innerKey]);
                copyValue(source, target, innerKey);
            }
        }
        var animator = new animation_Animator(source, false, additive ? existsAnimatorsOnSameTarget : null);
        animator.targetName = topKey;
        if (cfg.scope) {
            animator.scope = cfg.scope;
        }
        if (setToFinal && revertedSource) {
            animator.whenWithKeys(0, revertedSource, animatableKeys);
        }
        if (sourceClone) {
            animator.whenWithKeys(0, sourceClone, animatableKeys);
        }
        animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animatableKeys).delay(delay || 0);
        animatable.addAnimator(animator, topKey);
        animators.push(animator);
    }
}
/* harmony default export */ const lib_Element = (Element);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Displayable.js





var STYLE_MAGIC_KEY = '__zr_style_' + Math.round((Math.random() * 10));
var DEFAULT_COMMON_STYLE = {
    shadowBlur: 0,
    shadowOffsetX: 0,
    shadowOffsetY: 0,
    shadowColor: '#000',
    opacity: 1,
    blend: 'source-over'
};
var DEFAULT_COMMON_ANIMATION_PROPS = {
    style: {
        shadowBlur: true,
        shadowOffsetX: true,
        shadowOffsetY: true,
        shadowColor: true,
        opacity: true
    }
};
DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true;
var Displayable_PRIMARY_STATES_KEYS = ['z', 'z2', 'invisible'];
var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible'];
var Displayable = (function (_super) {
    __extends(Displayable, _super);
    function Displayable(props) {
        return _super.call(this, props) || this;
    }
    Displayable.prototype._init = function (props) {
        var keysArr = keys(props);
        for (var i = 0; i < keysArr.length; i++) {
            var key = keysArr[i];
            if (key === 'style') {
                this.useStyle(props[key]);
            }
            else {
                _super.prototype.attrKV.call(this, key, props[key]);
            }
        }
        if (!this.style) {
            this.useStyle({});
        }
    };
    Displayable.prototype.beforeBrush = function () { };
    Displayable.prototype.afterBrush = function () { };
    Displayable.prototype.innerBeforeBrush = function () { };
    Displayable.prototype.innerAfterBrush = function () { };
    Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) {
        var m = this.transform;
        if (this.ignore
            || this.invisible
            || this.style.opacity === 0
            || (this.culling
                && isDisplayableCulled(this, viewWidth, viewHeight))
            || (m && !m[0] && !m[3])) {
            return false;
        }
        if (considerClipPath && this.__clipPaths) {
            for (var i = 0; i < this.__clipPaths.length; ++i) {
                if (this.__clipPaths[i].isZeroArea()) {
                    return false;
                }
            }
        }
        if (considerAncestors && this.parent) {
            var parent_1 = this.parent;
            while (parent_1) {
                if (parent_1.ignore) {
                    return false;
                }
                parent_1 = parent_1.parent;
            }
        }
        return true;
    };
    Displayable.prototype.contain = function (x, y) {
        return this.rectContain(x, y);
    };
    Displayable.prototype.traverse = function (cb, context) {
        cb.call(context, this);
    };
    Displayable.prototype.rectContain = function (x, y) {
        var coord = this.transformCoordToLocal(x, y);
        var rect = this.getBoundingRect();
        return rect.contain(coord[0], coord[1]);
    };
    Displayable.prototype.getPaintRect = function () {
        var rect = this._paintRect;
        if (!this._paintRect || this.__dirty) {
            var transform = this.transform;
            var elRect = this.getBoundingRect();
            var style = this.style;
            var shadowSize = style.shadowBlur || 0;
            var shadowOffsetX = style.shadowOffsetX || 0;
            var shadowOffsetY = style.shadowOffsetY || 0;
            rect = this._paintRect || (this._paintRect = new core_BoundingRect(0, 0, 0, 0));
            if (transform) {
                core_BoundingRect.applyTransform(rect, elRect, transform);
            }
            else {
                rect.copy(elRect);
            }
            if (shadowSize || shadowOffsetX || shadowOffsetY) {
                rect.width += shadowSize * 2 + Math.abs(shadowOffsetX);
                rect.height += shadowSize * 2 + Math.abs(shadowOffsetY);
                rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize);
                rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize);
            }
            var tolerance = this.dirtyRectTolerance;
            if (!rect.isZero()) {
                rect.x = Math.floor(rect.x - tolerance);
                rect.y = Math.floor(rect.y - tolerance);
                rect.width = Math.ceil(rect.width + 1 + tolerance * 2);
                rect.height = Math.ceil(rect.height + 1 + tolerance * 2);
            }
        }
        return rect;
    };
    Displayable.prototype.setPrevPaintRect = function (paintRect) {
        if (paintRect) {
            this._prevPaintRect = this._prevPaintRect || new core_BoundingRect(0, 0, 0, 0);
            this._prevPaintRect.copy(paintRect);
        }
        else {
            this._prevPaintRect = null;
        }
    };
    Displayable.prototype.getPrevPaintRect = function () {
        return this._prevPaintRect;
    };
    Displayable.prototype.animateStyle = function (loop) {
        return this.animate('style', loop);
    };
    Displayable.prototype.updateDuringAnimation = function (targetKey) {
        if (targetKey === 'style') {
            this.dirtyStyle();
        }
        else {
            this.markRedraw();
        }
    };
    Displayable.prototype.attrKV = function (key, value) {
        if (key !== 'style') {
            _super.prototype.attrKV.call(this, key, value);
        }
        else {
            if (!this.style) {
                this.useStyle(value);
            }
            else {
                this.setStyle(value);
            }
        }
    };
    Displayable.prototype.setStyle = function (keyOrObj, value) {
        if (typeof keyOrObj === 'string') {
            this.style[keyOrObj] = value;
        }
        else {
            util_extend(this.style, keyOrObj);
        }
        this.dirtyStyle();
        return this;
    };
    Displayable.prototype.dirtyStyle = function (notRedraw) {
        if (!notRedraw) {
            this.markRedraw();
        }
        this.__dirty |= STYLE_CHANGED_BIT;
        if (this._rect) {
            this._rect = null;
        }
    };
    Displayable.prototype.dirty = function () {
        this.dirtyStyle();
    };
    Displayable.prototype.styleChanged = function () {
        return !!(this.__dirty & STYLE_CHANGED_BIT);
    };
    Displayable.prototype.styleUpdated = function () {
        this.__dirty &= ~STYLE_CHANGED_BIT;
    };
    Displayable.prototype.createStyle = function (obj) {
        return createObject(DEFAULT_COMMON_STYLE, obj);
    };
    Displayable.prototype.useStyle = function (obj) {
        if (!obj[STYLE_MAGIC_KEY]) {
            obj = this.createStyle(obj);
        }
        if (this.__inHover) {
            this.__hoverStyle = obj;
        }
        else {
            this.style = obj;
        }
        this.dirtyStyle();
    };
    Displayable.prototype.isStyleObject = function (obj) {
        return obj[STYLE_MAGIC_KEY];
    };
    Displayable.prototype._innerSaveToNormal = function (toState) {
        _super.prototype._innerSaveToNormal.call(this, toState);
        var normalState = this._normalState;
        if (toState.style && !normalState.style) {
            normalState.style = this._mergeStyle(this.createStyle(), this.style);
        }
        this._savePrimaryToNormal(toState, normalState, Displayable_PRIMARY_STATES_KEYS);
    };
    Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
        _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);
        var needsRestoreToNormal = !(state && keepCurrentStates);
        var targetStyle;
        if (state && state.style) {
            if (transition) {
                if (keepCurrentStates) {
                    targetStyle = state.style;
                }
                else {
                    targetStyle = this._mergeStyle(this.createStyle(), normalState.style);
                    this._mergeStyle(targetStyle, state.style);
                }
            }
            else {
                targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style);
                this._mergeStyle(targetStyle, state.style);
            }
        }
        else if (needsRestoreToNormal) {
            targetStyle = normalState.style;
        }
        if (targetStyle) {
            if (transition) {
                var sourceStyle = this.style;
                this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle);
                if (needsRestoreToNormal) {
                    var changedKeys = keys(sourceStyle);
                    for (var i = 0; i < changedKeys.length; i++) {
                        var key = changedKeys[i];
                        if (key in targetStyle) {
                            targetStyle[key] = targetStyle[key];
                            this.style[key] = sourceStyle[key];
                        }
                    }
                }
                var targetKeys = keys(targetStyle);
                for (var i = 0; i < targetKeys.length; i++) {
                    var key = targetKeys[i];
                    this.style[key] = this.style[key];
                }
                this._transitionState(stateName, {
                    style: targetStyle
                }, animationCfg, this.getAnimationStyleProps());
            }
            else {
                this.useStyle(targetStyle);
            }
        }
        var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : Displayable_PRIMARY_STATES_KEYS;
        for (var i = 0; i < statesKeys.length; i++) {
            var key = statesKeys[i];
            if (state && state[key] != null) {
                this[key] = state[key];
            }
            else if (needsRestoreToNormal) {
                if (normalState[key] != null) {
                    this[key] = normalState[key];
                }
            }
        }
    };
    Displayable.prototype._mergeStates = function (states) {
        var mergedState = _super.prototype._mergeStates.call(this, states);
        var mergedStyle;
        for (var i = 0; i < states.length; i++) {
            var state = states[i];
            if (state.style) {
                mergedStyle = mergedStyle || {};
                this._mergeStyle(mergedStyle, state.style);
            }
        }
        if (mergedStyle) {
            mergedState.style = mergedStyle;
        }
        return mergedState;
    };
    Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) {
        util_extend(targetStyle, sourceStyle);
        return targetStyle;
    };
    Displayable.prototype.getAnimationStyleProps = function () {
        return DEFAULT_COMMON_ANIMATION_PROPS;
    };
    Displayable.initDefaultProps = (function () {
        var dispProto = Displayable.prototype;
        dispProto.type = 'displayable';
        dispProto.invisible = false;
        dispProto.z = 0;
        dispProto.z2 = 0;
        dispProto.zlevel = 0;
        dispProto.culling = false;
        dispProto.cursor = 'pointer';
        dispProto.rectHover = false;
        dispProto.incremental = false;
        dispProto._rect = null;
        dispProto.dirtyRectTolerance = 0;
        dispProto.__dirty = REDARAW_BIT | STYLE_CHANGED_BIT;
    })();
    return Displayable;
}(lib_Element));
var tmpRect = new core_BoundingRect(0, 0, 0, 0);
var viewRect = new core_BoundingRect(0, 0, 0, 0);
function isDisplayableCulled(el, width, height) {
    tmpRect.copy(el.getBoundingRect());
    if (el.transform) {
        tmpRect.applyTransform(el.transform);
    }
    viewRect.width = width;
    viewRect.height = height;
    return !tmpRect.intersect(viewRect);
}
/* harmony default export */ const graphic_Displayable = (Displayable);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/curve.js

var mathPow = Math.pow;
var mathSqrt = Math.sqrt;
var curve_EPSILON = 1e-8;
var EPSILON_NUMERIC = 1e-4;
var THREE_SQRT = mathSqrt(3);
var ONE_THIRD = 1 / 3;
var _v0 = vector_create();
var _v1 = vector_create();
var _v2 = vector_create();
function isAroundZero(val) {
    return val > -curve_EPSILON && val < curve_EPSILON;
}
function curve_isNotAroundZero(val) {
    return val > curve_EPSILON || val < -curve_EPSILON;
}
function curve_cubicAt(p0, p1, p2, p3, t) {
    var onet = 1 - t;
    return onet * onet * (onet * p0 + 3 * t * p1)
        + t * t * (t * p3 + 3 * onet * p2);
}
function cubicDerivativeAt(p0, p1, p2, p3, t) {
    var onet = 1 - t;
    return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet
        + (p3 - p2) * t * t);
}
function cubicRootAt(p0, p1, p2, p3, val, roots) {
    var a = p3 + 3 * (p1 - p2) - p0;
    var b = 3 * (p2 - p1 * 2 + p0);
    var c = 3 * (p1 - p0);
    var d = p0 - val;
    var A = b * b - 3 * a * c;
    var B = b * c - 9 * a * d;
    var C = c * c - 3 * b * d;
    var n = 0;
    if (isAroundZero(A) && isAroundZero(B)) {
        if (isAroundZero(b)) {
            roots[0] = 0;
        }
        else {
            var t1 = -c / b;
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
        }
    }
    else {
        var disc = B * B - 4 * A * C;
        if (isAroundZero(disc)) {
            var K = B / A;
            var t1 = -b / a + K;
            var t2 = -K / 2;
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
            if (t2 >= 0 && t2 <= 1) {
                roots[n++] = t2;
            }
        }
        else if (disc > 0) {
            var discSqrt = mathSqrt(disc);
            var Y1 = A * b + 1.5 * a * (-B + discSqrt);
            var Y2 = A * b + 1.5 * a * (-B - discSqrt);
            if (Y1 < 0) {
                Y1 = -mathPow(-Y1, ONE_THIRD);
            }
            else {
                Y1 = mathPow(Y1, ONE_THIRD);
            }
            if (Y2 < 0) {
                Y2 = -mathPow(-Y2, ONE_THIRD);
            }
            else {
                Y2 = mathPow(Y2, ONE_THIRD);
            }
            var t1 = (-b - (Y1 + Y2)) / (3 * a);
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
        }
        else {
            var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A));
            var theta = Math.acos(T) / 3;
            var ASqrt = mathSqrt(A);
            var tmp = Math.cos(theta);
            var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
            var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
            var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
            if (t2 >= 0 && t2 <= 1) {
                roots[n++] = t2;
            }
            if (t3 >= 0 && t3 <= 1) {
                roots[n++] = t3;
            }
        }
    }
    return n;
}
function curve_cubicExtrema(p0, p1, p2, p3, extrema) {
    var b = 6 * p2 - 12 * p1 + 6 * p0;
    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
    var c = 3 * p1 - 3 * p0;
    var n = 0;
    if (isAroundZero(a)) {
        if (curve_isNotAroundZero(b)) {
            var t1 = -c / b;
            if (t1 >= 0 && t1 <= 1) {
                extrema[n++] = t1;
            }
        }
    }
    else {
        var disc = b * b - 4 * a * c;
        if (isAroundZero(disc)) {
            extrema[0] = -b / (2 * a);
        }
        else if (disc > 0) {
            var discSqrt = mathSqrt(disc);
            var t1 = (-b + discSqrt) / (2 * a);
            var t2 = (-b - discSqrt) / (2 * a);
            if (t1 >= 0 && t1 <= 1) {
                extrema[n++] = t1;
            }
            if (t2 >= 0 && t2 <= 1) {
                extrema[n++] = t2;
            }
        }
    }
    return n;
}
function cubicSubdivide(p0, p1, p2, p3, t, out) {
    var p01 = (p1 - p0) * t + p0;
    var p12 = (p2 - p1) * t + p1;
    var p23 = (p3 - p2) * t + p2;
    var p012 = (p12 - p01) * t + p01;
    var p123 = (p23 - p12) * t + p12;
    var p0123 = (p123 - p012) * t + p012;
    out[0] = p0;
    out[1] = p01;
    out[2] = p012;
    out[3] = p0123;
    out[4] = p0123;
    out[5] = p123;
    out[6] = p23;
    out[7] = p3;
}
function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) {
    var t;
    var interval = 0.005;
    var d = Infinity;
    var prev;
    var next;
    var d1;
    var d2;
    _v0[0] = x;
    _v0[1] = y;
    for (var _t = 0; _t < 1; _t += 0.05) {
        _v1[0] = curve_cubicAt(x0, x1, x2, x3, _t);
        _v1[1] = curve_cubicAt(y0, y1, y2, y3, _t);
        d1 = distSquare(_v0, _v1);
        if (d1 < d) {
            t = _t;
            d = d1;
        }
    }
    d = Infinity;
    for (var i = 0; i < 32; i++) {
        if (interval < EPSILON_NUMERIC) {
            break;
        }
        prev = t - interval;
        next = t + interval;
        _v1[0] = curve_cubicAt(x0, x1, x2, x3, prev);
        _v1[1] = curve_cubicAt(y0, y1, y2, y3, prev);
        d1 = distSquare(_v1, _v0);
        if (prev >= 0 && d1 < d) {
            t = prev;
            d = d1;
        }
        else {
            _v2[0] = curve_cubicAt(x0, x1, x2, x3, next);
            _v2[1] = curve_cubicAt(y0, y1, y2, y3, next);
            d2 = distSquare(_v2, _v0);
            if (next <= 1 && d2 < d) {
                t = next;
                d = d2;
            }
            else {
                interval *= 0.5;
            }
        }
    }
    if (out) {
        out[0] = curve_cubicAt(x0, x1, x2, x3, t);
        out[1] = curve_cubicAt(y0, y1, y2, y3, t);
    }
    return mathSqrt(d);
}
function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) {
    var px = x0;
    var py = y0;
    var d = 0;
    var step = 1 / iteration;
    for (var i = 1; i <= iteration; i++) {
        var t = i * step;
        var x = curve_cubicAt(x0, x1, x2, x3, t);
        var y = curve_cubicAt(y0, y1, y2, y3, t);
        var dx = x - px;
        var dy = y - py;
        d += Math.sqrt(dx * dx + dy * dy);
        px = x;
        py = y;
    }
    return d;
}
function curve_quadraticAt(p0, p1, p2, t) {
    var onet = 1 - t;
    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
}
function quadraticDerivativeAt(p0, p1, p2, t) {
    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
}
function quadraticRootAt(p0, p1, p2, val, roots) {
    var a = p0 - 2 * p1 + p2;
    var b = 2 * (p1 - p0);
    var c = p0 - val;
    var n = 0;
    if (isAroundZero(a)) {
        if (curve_isNotAroundZero(b)) {
            var t1 = -c / b;
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
        }
    }
    else {
        var disc = b * b - 4 * a * c;
        if (isAroundZero(disc)) {
            var t1 = -b / (2 * a);
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
        }
        else if (disc > 0) {
            var discSqrt = mathSqrt(disc);
            var t1 = (-b + discSqrt) / (2 * a);
            var t2 = (-b - discSqrt) / (2 * a);
            if (t1 >= 0 && t1 <= 1) {
                roots[n++] = t1;
            }
            if (t2 >= 0 && t2 <= 1) {
                roots[n++] = t2;
            }
        }
    }
    return n;
}
function curve_quadraticExtremum(p0, p1, p2) {
    var divider = p0 + p2 - 2 * p1;
    if (divider === 0) {
        return 0.5;
    }
    else {
        return (p0 - p1) / divider;
    }
}
function quadraticSubdivide(p0, p1, p2, t, out) {
    var p01 = (p1 - p0) * t + p0;
    var p12 = (p2 - p1) * t + p1;
    var p012 = (p12 - p01) * t + p01;
    out[0] = p0;
    out[1] = p01;
    out[2] = p012;
    out[3] = p012;
    out[4] = p12;
    out[5] = p2;
}
function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) {
    var t;
    var interval = 0.005;
    var d = Infinity;
    _v0[0] = x;
    _v0[1] = y;
    for (var _t = 0; _t < 1; _t += 0.05) {
        _v1[0] = curve_quadraticAt(x0, x1, x2, _t);
        _v1[1] = curve_quadraticAt(y0, y1, y2, _t);
        var d1 = distSquare(_v0, _v1);
        if (d1 < d) {
            t = _t;
            d = d1;
        }
    }
    d = Infinity;
    for (var i = 0; i < 32; i++) {
        if (interval < EPSILON_NUMERIC) {
            break;
        }
        var prev = t - interval;
        var next = t + interval;
        _v1[0] = curve_quadraticAt(x0, x1, x2, prev);
        _v1[1] = curve_quadraticAt(y0, y1, y2, prev);
        var d1 = distSquare(_v1, _v0);
        if (prev >= 0 && d1 < d) {
            t = prev;
            d = d1;
        }
        else {
            _v2[0] = curve_quadraticAt(x0, x1, x2, next);
            _v2[1] = curve_quadraticAt(y0, y1, y2, next);
            var d2 = distSquare(_v2, _v0);
            if (next <= 1 && d2 < d) {
                t = next;
                d = d2;
            }
            else {
                interval *= 0.5;
            }
        }
    }
    if (out) {
        out[0] = curve_quadraticAt(x0, x1, x2, t);
        out[1] = curve_quadraticAt(y0, y1, y2, t);
    }
    return mathSqrt(d);
}
function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) {
    var px = x0;
    var py = y0;
    var d = 0;
    var step = 1 / iteration;
    for (var i = 1; i <= iteration; i++) {
        var t = i * step;
        var x = curve_quadraticAt(x0, x1, x2, t);
        var y = curve_quadraticAt(y0, y1, y2, t);
        var dx = x - px;
        var dy = y - py;
        d += Math.sqrt(dx * dx + dy * dy);
        px = x;
        py = y;
    }
    return d;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/bbox.js


var bbox_mathMin = Math.min;
var bbox_mathMax = Math.max;
var mathSin = Math.sin;
var mathCos = Math.cos;
var PI2 = Math.PI * 2;
var start = vector_create();
var end = vector_create();
var extremity = vector_create();
function fromPoints(points, min, max) {
    if (points.length === 0) {
        return;
    }
    var p = points[0];
    var left = p[0];
    var right = p[0];
    var top = p[1];
    var bottom = p[1];
    for (var i = 1; i < points.length; i++) {
        p = points[i];
        left = bbox_mathMin(left, p[0]);
        right = bbox_mathMax(right, p[0]);
        top = bbox_mathMin(top, p[1]);
        bottom = bbox_mathMax(bottom, p[1]);
    }
    min[0] = left;
    min[1] = top;
    max[0] = right;
    max[1] = bottom;
}
function fromLine(x0, y0, x1, y1, min, max) {
    min[0] = bbox_mathMin(x0, x1);
    min[1] = bbox_mathMin(y0, y1);
    max[0] = bbox_mathMax(x0, x1);
    max[1] = bbox_mathMax(y0, y1);
}
var xDim = [];
var yDim = [];
function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min, max) {
    var cubicExtrema = curve_cubicExtrema;
    var cubicAt = curve_cubicAt;
    var n = cubicExtrema(x0, x1, x2, x3, xDim);
    min[0] = Infinity;
    min[1] = Infinity;
    max[0] = -Infinity;
    max[1] = -Infinity;
    for (var i = 0; i < n; i++) {
        var x = cubicAt(x0, x1, x2, x3, xDim[i]);
        min[0] = bbox_mathMin(x, min[0]);
        max[0] = bbox_mathMax(x, max[0]);
    }
    n = cubicExtrema(y0, y1, y2, y3, yDim);
    for (var i = 0; i < n; i++) {
        var y = cubicAt(y0, y1, y2, y3, yDim[i]);
        min[1] = bbox_mathMin(y, min[1]);
        max[1] = bbox_mathMax(y, max[1]);
    }
    min[0] = bbox_mathMin(x0, min[0]);
    max[0] = bbox_mathMax(x0, max[0]);
    min[0] = bbox_mathMin(x3, min[0]);
    max[0] = bbox_mathMax(x3, max[0]);
    min[1] = bbox_mathMin(y0, min[1]);
    max[1] = bbox_mathMax(y0, max[1]);
    min[1] = bbox_mathMin(y3, min[1]);
    max[1] = bbox_mathMax(y3, max[1]);
}
function fromQuadratic(x0, y0, x1, y1, x2, y2, min, max) {
    var quadraticExtremum = curve_quadraticExtremum;
    var quadraticAt = curve_quadraticAt;
    var tx = bbox_mathMax(bbox_mathMin(quadraticExtremum(x0, x1, x2), 1), 0);
    var ty = bbox_mathMax(bbox_mathMin(quadraticExtremum(y0, y1, y2), 1), 0);
    var x = quadraticAt(x0, x1, x2, tx);
    var y = quadraticAt(y0, y1, y2, ty);
    min[0] = bbox_mathMin(x0, x2, x);
    min[1] = bbox_mathMin(y0, y2, y);
    max[0] = bbox_mathMax(x0, x2, x);
    max[1] = bbox_mathMax(y0, y2, y);
}
function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min, max) {
    var vec2Min = vector_min;
    var vec2Max = vector_max;
    var diff = Math.abs(startAngle - endAngle);
    if (diff % PI2 < 1e-4 && diff > 1e-4) {
        min[0] = x - rx;
        min[1] = y - ry;
        max[0] = x + rx;
        max[1] = y + ry;
        return;
    }
    start[0] = mathCos(startAngle) * rx + x;
    start[1] = mathSin(startAngle) * ry + y;
    end[0] = mathCos(endAngle) * rx + x;
    end[1] = mathSin(endAngle) * ry + y;
    vec2Min(min, start, end);
    vec2Max(max, start, end);
    startAngle = startAngle % (PI2);
    if (startAngle < 0) {
        startAngle = startAngle + PI2;
    }
    endAngle = endAngle % (PI2);
    if (endAngle < 0) {
        endAngle = endAngle + PI2;
    }
    if (startAngle > endAngle && !anticlockwise) {
        endAngle += PI2;
    }
    else if (startAngle < endAngle && anticlockwise) {
        startAngle += PI2;
    }
    if (anticlockwise) {
        var tmp = endAngle;
        endAngle = startAngle;
        startAngle = tmp;
    }
    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
        if (angle > startAngle) {
            extremity[0] = mathCos(angle) * rx + x;
            extremity[1] = mathSin(angle) * ry + y;
            vec2Min(min, extremity, min);
            vec2Max(max, extremity, max);
        }
    }
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/PathProxy.js





var CMD = {
    M: 1,
    L: 2,
    C: 3,
    Q: 4,
    A: 5,
    Z: 6,
    R: 7
};
var tmpOutX = [];
var tmpOutY = [];
var min = [];
var max = [];
var min2 = [];
var max2 = [];
var PathProxy_mathMin = Math.min;
var PathProxy_mathMax = Math.max;
var PathProxy_mathCos = Math.cos;
var PathProxy_mathSin = Math.sin;
var PathProxy_mathSqrt = Math.sqrt;
var mathAbs = Math.abs;
var PI = Math.PI;
var PathProxy_PI2 = PI * 2;
var hasTypedArray = typeof Float32Array !== 'undefined';
var tmpAngles = [];
function modPI2(radian) {
    var n = Math.round(radian / PI * 1e8) / 1e8;
    return (n % 2) * PI;
}
function normalizeArcAngles(angles, anticlockwise) {
    var newStartAngle = modPI2(angles[0]);
    if (newStartAngle < 0) {
        newStartAngle += PathProxy_PI2;
    }
    var delta = newStartAngle - angles[0];
    var newEndAngle = angles[1];
    newEndAngle += delta;
    if (!anticlockwise && newEndAngle - newStartAngle >= PathProxy_PI2) {
        newEndAngle = newStartAngle + PathProxy_PI2;
    }
    else if (anticlockwise && newStartAngle - newEndAngle >= PathProxy_PI2) {
        newEndAngle = newStartAngle - PathProxy_PI2;
    }
    else if (!anticlockwise && newStartAngle > newEndAngle) {
        newEndAngle = newStartAngle + (PathProxy_PI2 - modPI2(newStartAngle - newEndAngle));
    }
    else if (anticlockwise && newStartAngle < newEndAngle) {
        newEndAngle = newStartAngle - (PathProxy_PI2 - modPI2(newEndAngle - newStartAngle));
    }
    angles[0] = newStartAngle;
    angles[1] = newEndAngle;
}
var PathProxy = (function () {
    function PathProxy(notSaveData) {
        this.dpr = 1;
        this._xi = 0;
        this._yi = 0;
        this._x0 = 0;
        this._y0 = 0;
        this._len = 0;
        if (notSaveData) {
            this._saveData = false;
        }
        if (this._saveData) {
            this.data = [];
        }
    }
    PathProxy.prototype.increaseVersion = function () {
        this._version++;
    };
    PathProxy.prototype.getVersion = function () {
        return this._version;
    };
    PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) {
        segmentIgnoreThreshold = segmentIgnoreThreshold || 0;
        if (segmentIgnoreThreshold > 0) {
            this._ux = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sx) || 0;
            this._uy = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sy) || 0;
        }
    };
    PathProxy.prototype.setDPR = function (dpr) {
        this.dpr = dpr;
    };
    PathProxy.prototype.setContext = function (ctx) {
        this._ctx = ctx;
    };
    PathProxy.prototype.getContext = function () {
        return this._ctx;
    };
    PathProxy.prototype.beginPath = function () {
        this._ctx && this._ctx.beginPath();
        this.reset();
        return this;
    };
    PathProxy.prototype.reset = function () {
        if (this._saveData) {
            this._len = 0;
        }
        if (this._lineDash) {
            this._lineDash = null;
            this._dashOffset = 0;
        }
        if (this._pathSegLen) {
            this._pathSegLen = null;
            this._pathLen = 0;
        }
        this._version++;
    };
    PathProxy.prototype.moveTo = function (x, y) {
        this._drawPendingPt();
        this.addData(CMD.M, x, y);
        this._ctx && this._ctx.moveTo(x, y);
        this._x0 = x;
        this._y0 = y;
        this._xi = x;
        this._yi = y;
        return this;
    };
    PathProxy.prototype.lineTo = function (x, y) {
        var dx = mathAbs(x - this._xi);
        var dy = mathAbs(y - this._yi);
        var exceedUnit = dx > this._ux || dy > this._uy;
        this.addData(CMD.L, x, y);
        if (this._ctx && exceedUnit) {
            this._needsDash ? this._dashedLineTo(x, y)
                : this._ctx.lineTo(x, y);
        }
        if (exceedUnit) {
            this._xi = x;
            this._yi = y;
            this._pendingPtDist = 0;
        }
        else {
            var d2 = dx * dx + dy * dy;
            if (d2 > this._pendingPtDist) {
                this._pendingPtX = x;
                this._pendingPtY = y;
                this._pendingPtDist = d2;
            }
        }
        return this;
    };
    PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) {
        this.addData(CMD.C, x1, y1, x2, y2, x3, y3);
        if (this._ctx) {
            this._needsDash ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
                : this._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
        }
        this._xi = x3;
        this._yi = y3;
        return this;
    };
    PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) {
        this.addData(CMD.Q, x1, y1, x2, y2);
        if (this._ctx) {
            this._needsDash ? this._dashedQuadraticTo(x1, y1, x2, y2)
                : this._ctx.quadraticCurveTo(x1, y1, x2, y2);
        }
        this._xi = x2;
        this._yi = y2;
        return this;
    };
    PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) {
        tmpAngles[0] = startAngle;
        tmpAngles[1] = endAngle;
        normalizeArcAngles(tmpAngles, anticlockwise);
        startAngle = tmpAngles[0];
        endAngle = tmpAngles[1];
        var delta = endAngle - startAngle;
        this.addData(CMD.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1);
        this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
        this._xi = PathProxy_mathCos(endAngle) * r + cx;
        this._yi = PathProxy_mathSin(endAngle) * r + cy;
        return this;
    };
    PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) {
        if (this._ctx) {
            this._ctx.arcTo(x1, y1, x2, y2, radius);
        }
        return this;
    };
    PathProxy.prototype.rect = function (x, y, w, h) {
        this._ctx && this._ctx.rect(x, y, w, h);
        this.addData(CMD.R, x, y, w, h);
        return this;
    };
    PathProxy.prototype.closePath = function () {
        this._drawPendingPt();
        this.addData(CMD.Z);
        var ctx = this._ctx;
        var x0 = this._x0;
        var y0 = this._y0;
        if (ctx) {
            this._needsDash && this._dashedLineTo(x0, y0);
            ctx.closePath();
        }
        this._xi = x0;
        this._yi = y0;
        return this;
    };
    PathProxy.prototype.fill = function (ctx) {
        ctx && ctx.fill();
        this.toStatic();
    };
    PathProxy.prototype.stroke = function (ctx) {
        ctx && ctx.stroke();
        this.toStatic();
    };
    PathProxy.prototype.setLineDash = function (lineDash) {
        if (lineDash instanceof Array) {
            this._lineDash = lineDash;
            this._dashIdx = 0;
            var lineDashSum = 0;
            for (var i = 0; i < lineDash.length; i++) {
                lineDashSum += lineDash[i];
            }
            this._dashSum = lineDashSum;
            this._needsDash = true;
        }
        else {
            this._lineDash = null;
            this._needsDash = false;
        }
        return this;
    };
    PathProxy.prototype.setLineDashOffset = function (offset) {
        this._dashOffset = offset;
        return this;
    };
    PathProxy.prototype.len = function () {
        return this._len;
    };
    PathProxy.prototype.setData = function (data) {
        var len = data.length;
        if (!(this.data && this.data.length === len) && hasTypedArray) {
            this.data = new Float32Array(len);
        }
        for (var i = 0; i < len; i++) {
            this.data[i] = data[i];
        }
        this._len = len;
    };
    PathProxy.prototype.appendPath = function (path) {
        if (!(path instanceof Array)) {
            path = [path];
        }
        var len = path.length;
        var appendSize = 0;
        var offset = this._len;
        for (var i = 0; i < len; i++) {
            appendSize += path[i].len();
        }
        if (hasTypedArray && (this.data instanceof Float32Array)) {
            this.data = new Float32Array(offset + appendSize);
        }
        for (var i = 0; i < len; i++) {
            var appendPathData = path[i].data;
            for (var k = 0; k < appendPathData.length; k++) {
                this.data[offset++] = appendPathData[k];
            }
        }
        this._len = offset;
    };
    PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) {
        if (!this._saveData) {
            return;
        }
        var data = this.data;
        if (this._len + arguments.length > data.length) {
            this._expandData();
            data = this.data;
        }
        for (var i = 0; i < arguments.length; i++) {
            data[this._len++] = arguments[i];
        }
    };
    PathProxy.prototype._drawPendingPt = function () {
        if (this._pendingPtDist > 0) {
            this._ctx && this._ctx.lineTo(this._pendingPtX, this._pendingPtY);
            this._pendingPtDist = 0;
        }
    };
    PathProxy.prototype._expandData = function () {
        if (!(this.data instanceof Array)) {
            var newData = [];
            for (var i = 0; i < this._len; i++) {
                newData[i] = this.data[i];
            }
            this.data = newData;
        }
    };
    PathProxy.prototype._dashedLineTo = function (x1, y1) {
        var dashSum = this._dashSum;
        var lineDash = this._lineDash;
        var ctx = this._ctx;
        var offset = this._dashOffset;
        var x0 = this._xi;
        var y0 = this._yi;
        var dx = x1 - x0;
        var dy = y1 - y0;
        var dist = PathProxy_mathSqrt(dx * dx + dy * dy);
        var x = x0;
        var y = y0;
        var nDash = lineDash.length;
        var dash;
        var idx;
        dx /= dist;
        dy /= dist;
        if (offset < 0) {
            offset = dashSum + offset;
        }
        offset %= dashSum;
        x -= offset * dx;
        y -= offset * dy;
        while ((dx > 0 && x <= x1) || (dx < 0 && x >= x1)
            || (dx === 0 && ((dy > 0 && y <= y1) || (dy < 0 && y >= y1)))) {
            idx = this._dashIdx;
            dash = lineDash[idx];
            x += dx * dash;
            y += dy * dash;
            this._dashIdx = (idx + 1) % nDash;
            if ((dx > 0 && x < x0) || (dx < 0 && x > x0) || (dy > 0 && y < y0) || (dy < 0 && y > y0)) {
                continue;
            }
            ctx[idx % 2 ? 'moveTo' : 'lineTo'](dx >= 0 ? PathProxy_mathMin(x, x1) : PathProxy_mathMax(x, x1), dy >= 0 ? PathProxy_mathMin(y, y1) : PathProxy_mathMax(y, y1));
        }
        dx = x - x1;
        dy = y - y1;
        this._dashOffset = -PathProxy_mathSqrt(dx * dx + dy * dy);
    };
    PathProxy.prototype._dashedBezierTo = function (x1, y1, x2, y2, x3, y3) {
        var ctx = this._ctx;
        var dashSum = this._dashSum;
        var offset = this._dashOffset;
        var lineDash = this._lineDash;
        var x0 = this._xi;
        var y0 = this._yi;
        var bezierLen = 0;
        var idx = this._dashIdx;
        var nDash = lineDash.length;
        var t;
        var dx;
        var dy;
        var x;
        var y;
        var tmpLen = 0;
        if (offset < 0) {
            offset = dashSum + offset;
        }
        offset %= dashSum;
        for (t = 0; t < 1; t += 0.1) {
            dx = curve_cubicAt(x0, x1, x2, x3, t + 0.1)
                - curve_cubicAt(x0, x1, x2, x3, t);
            dy = curve_cubicAt(y0, y1, y2, y3, t + 0.1)
                - curve_cubicAt(y0, y1, y2, y3, t);
            bezierLen += PathProxy_mathSqrt(dx * dx + dy * dy);
        }
        for (; idx < nDash; idx++) {
            tmpLen += lineDash[idx];
            if (tmpLen > offset) {
                break;
            }
        }
        t = (tmpLen - offset) / bezierLen;
        while (t <= 1) {
            x = curve_cubicAt(x0, x1, x2, x3, t);
            y = curve_cubicAt(y0, y1, y2, y3, t);
            idx % 2 ? ctx.moveTo(x, y)
                : ctx.lineTo(x, y);
            t += lineDash[idx] / bezierLen;
            idx = (idx + 1) % nDash;
        }
        (idx % 2 !== 0) && ctx.lineTo(x3, y3);
        dx = x3 - x;
        dy = y3 - y;
        this._dashOffset = -PathProxy_mathSqrt(dx * dx + dy * dy);
    };
    PathProxy.prototype._dashedQuadraticTo = function (x1, y1, x2, y2) {
        var x3 = x2;
        var y3 = y2;
        x2 = (x2 + 2 * x1) / 3;
        y2 = (y2 + 2 * y1) / 3;
        x1 = (this._xi + 2 * x1) / 3;
        y1 = (this._yi + 2 * y1) / 3;
        this._dashedBezierTo(x1, y1, x2, y2, x3, y3);
    };
    PathProxy.prototype.toStatic = function () {
        if (!this._saveData) {
            return;
        }
        this._drawPendingPt();
        var data = this.data;
        if (data instanceof Array) {
            data.length = this._len;
            if (hasTypedArray && this._len > 11) {
                this.data = new Float32Array(data);
            }
        }
    };
    PathProxy.prototype.getBoundingRect = function () {
        min[0] = min[1] = min2[0] = min2[1] = Number.MAX_VALUE;
        max[0] = max[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
        var data = this.data;
        var xi = 0;
        var yi = 0;
        var x0 = 0;
        var y0 = 0;
        var i;
        for (i = 0; i < this._len;) {
            var cmd = data[i++];
            var isFirst = i === 1;
            if (isFirst) {
                xi = data[i];
                yi = data[i + 1];
                x0 = xi;
                y0 = yi;
            }
            switch (cmd) {
                case CMD.M:
                    xi = x0 = data[i++];
                    yi = y0 = data[i++];
                    min2[0] = x0;
                    min2[1] = y0;
                    max2[0] = x0;
                    max2[1] = y0;
                    break;
                case CMD.L:
                    fromLine(xi, yi, data[i], data[i + 1], min2, max2);
                    xi = data[i++];
                    yi = data[i++];
                    break;
                case CMD.C:
                    fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2);
                    xi = data[i++];
                    yi = data[i++];
                    break;
                case CMD.Q:
                    fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2);
                    xi = data[i++];
                    yi = data[i++];
                    break;
                case CMD.A:
                    var cx = data[i++];
                    var cy = data[i++];
                    var rx = data[i++];
                    var ry = data[i++];
                    var startAngle = data[i++];
                    var endAngle = data[i++] + startAngle;
                    i += 1;
                    var anticlockwise = !data[i++];
                    if (isFirst) {
                        x0 = PathProxy_mathCos(startAngle) * rx + cx;
                        y0 = PathProxy_mathSin(startAngle) * ry + cy;
                    }
                    fromArc(cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2);
                    xi = PathProxy_mathCos(endAngle) * rx + cx;
                    yi = PathProxy_mathSin(endAngle) * ry + cy;
                    break;
                case CMD.R:
                    x0 = xi = data[i++];
                    y0 = yi = data[i++];
                    var width = data[i++];
                    var height = data[i++];
                    fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
                    break;
                case CMD.Z:
                    xi = x0;
                    yi = y0;
                    break;
            }
            vector_min(min, min, min2);
            vector_max(max, max, max2);
        }
        if (i === 0) {
            min[0] = min[1] = max[0] = max[1] = 0;
        }
        return new core_BoundingRect(min[0], min[1], max[0] - min[0], max[1] - min[1]);
    };
    PathProxy.prototype._calculateLength = function () {
        var data = this.data;
        var len = this._len;
        var ux = this._ux;
        var uy = this._uy;
        var xi = 0;
        var yi = 0;
        var x0 = 0;
        var y0 = 0;
        if (!this._pathSegLen) {
            this._pathSegLen = [];
        }
        var pathSegLen = this._pathSegLen;
        var pathTotalLen = 0;
        var segCount = 0;
        for (var i = 0; i < len;) {
            var cmd = data[i++];
            var isFirst = i === 1;
            if (isFirst) {
                xi = data[i];
                yi = data[i + 1];
                x0 = xi;
                y0 = yi;
            }
            var l = -1;
            switch (cmd) {
                case CMD.M:
                    xi = x0 = data[i++];
                    yi = y0 = data[i++];
                    break;
                case CMD.L: {
                    var x2 = data[i++];
                    var y2 = data[i++];
                    var dx = x2 - xi;
                    var dy = y2 - yi;
                    if (mathAbs(dx) > ux || mathAbs(dy) > uy || i === len - 1) {
                        l = Math.sqrt(dx * dx + dy * dy);
                        xi = x2;
                        yi = y2;
                    }
                    break;
                }
                case CMD.C: {
                    var x1 = data[i++];
                    var y1 = data[i++];
                    var x2 = data[i++];
                    var y2 = data[i++];
                    var x3 = data[i++];
                    var y3 = data[i++];
                    l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10);
                    xi = x3;
                    yi = y3;
                    break;
                }
                case CMD.Q: {
                    var x1 = data[i++];
                    var y1 = data[i++];
                    var x2 = data[i++];
                    var y2 = data[i++];
                    l = quadraticLength(xi, yi, x1, y1, x2, y2, 10);
                    xi = x2;
                    yi = y2;
                    break;
                }
                case CMD.A:
                    var cx = data[i++];
                    var cy = data[i++];
                    var rx = data[i++];
                    var ry = data[i++];
                    var startAngle = data[i++];
                    var delta = data[i++];
                    var endAngle = delta + startAngle;
                    i += 1;
                    var anticlockwise = !data[i++];
                    if (isFirst) {
                        x0 = PathProxy_mathCos(startAngle) * rx + cx;
                        y0 = PathProxy_mathSin(startAngle) * ry + cy;
                    }
                    l = PathProxy_mathMax(rx, ry) * PathProxy_mathMin(PathProxy_PI2, Math.abs(delta));
                    xi = PathProxy_mathCos(endAngle) * rx + cx;
                    yi = PathProxy_mathSin(endAngle) * ry + cy;
                    break;
                case CMD.R: {
                    x0 = xi = data[i++];
                    y0 = yi = data[i++];
                    var width = data[i++];
                    var height = data[i++];
                    l = width * 2 + height * 2;
                    break;
                }
                case CMD.Z: {
                    var dx = x0 - xi;
                    var dy = y0 - yi;
                    l = Math.sqrt(dx * dx + dy * dy);
                    xi = x0;
                    yi = y0;
                    break;
                }
            }
            if (l >= 0) {
                pathSegLen[segCount++] = l;
                pathTotalLen += l;
            }
        }
        this._pathLen = pathTotalLen;
        return pathTotalLen;
    };
    PathProxy.prototype.rebuildPath = function (ctx, percent) {
        var d = this.data;
        var ux = this._ux;
        var uy = this._uy;
        var len = this._len;
        var x0;
        var y0;
        var xi;
        var yi;
        var x;
        var y;
        var drawPart = percent < 1;
        var pathSegLen;
        var pathTotalLen;
        var accumLength = 0;
        var segCount = 0;
        var displayedLength;
        var pendingPtDist = 0;
        var pendingPtX;
        var pendingPtY;
        if (drawPart) {
            if (!this._pathSegLen) {
                this._calculateLength();
            }
            pathSegLen = this._pathSegLen;
            pathTotalLen = this._pathLen;
            displayedLength = percent * pathTotalLen;
            if (!displayedLength) {
                return;
            }
        }
        lo: for (var i = 0; i < len;) {
            var cmd = d[i++];
            var isFirst = i === 1;
            if (isFirst) {
                xi = d[i];
                yi = d[i + 1];
                x0 = xi;
                y0 = yi;
            }
            switch (cmd) {
                case CMD.M:
                    if (pendingPtDist > 0) {
                        ctx.lineTo(pendingPtX, pendingPtY);
                        pendingPtDist = 0;
                    }
                    x0 = xi = d[i++];
                    y0 = yi = d[i++];
                    ctx.moveTo(xi, yi);
                    break;
                case CMD.L: {
                    x = d[i++];
                    y = d[i++];
                    var dx = mathAbs(x - xi);
                    var dy = mathAbs(y - yi);
                    if (dx > ux || dy > uy) {
                        if (drawPart) {
                            var l = pathSegLen[segCount++];
                            if (accumLength + l > displayedLength) {
                                var t = (displayedLength - accumLength) / l;
                                ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t);
                                break lo;
                            }
                            accumLength += l;
                        }
                        ctx.lineTo(x, y);
                        xi = x;
                        yi = y;
                        pendingPtDist = 0;
                    }
                    else {
                        var d2 = dx * dx + dy * dy;
                        if (d2 > pendingPtDist) {
                            pendingPtX = x;
                            pendingPtY = y;
                            pendingPtDist = d2;
                        }
                    }
                    break;
                }
                case CMD.C: {
                    var x1 = d[i++];
                    var y1 = d[i++];
                    var x2 = d[i++];
                    var y2 = d[i++];
                    var x3 = d[i++];
                    var y3 = d[i++];
                    if (drawPart) {
                        var l = pathSegLen[segCount++];
                        if (accumLength + l > displayedLength) {
                            var t = (displayedLength - accumLength) / l;
                            cubicSubdivide(xi, x1, x2, x3, t, tmpOutX);
                            cubicSubdivide(yi, y1, y2, y3, t, tmpOutY);
                            ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]);
                            break lo;
                        }
                        accumLength += l;
                    }
                    ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
                    xi = x3;
                    yi = y3;
                    break;
                }
                case CMD.Q: {
                    var x1 = d[i++];
                    var y1 = d[i++];
                    var x2 = d[i++];
                    var y2 = d[i++];
                    if (drawPart) {
                        var l = pathSegLen[segCount++];
                        if (accumLength + l > displayedLength) {
                            var t = (displayedLength - accumLength) / l;
                            quadraticSubdivide(xi, x1, x2, t, tmpOutX);
                            quadraticSubdivide(yi, y1, y2, t, tmpOutY);
                            ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]);
                            break lo;
                        }
                        accumLength += l;
                    }
                    ctx.quadraticCurveTo(x1, y1, x2, y2);
                    xi = x2;
                    yi = y2;
                    break;
                }
                case CMD.A:
                    var cx = d[i++];
                    var cy = d[i++];
                    var rx = d[i++];
                    var ry = d[i++];
                    var startAngle = d[i++];
                    var delta = d[i++];
                    var psi = d[i++];
                    var anticlockwise = !d[i++];
                    var r = (rx > ry) ? rx : ry;
                    var scaleX = (rx > ry) ? 1 : rx / ry;
                    var scaleY = (rx > ry) ? ry / rx : 1;
                    var isEllipse = mathAbs(rx - ry) > 1e-3;
                    var endAngle = startAngle + delta;
                    var breakBuild = false;
                    if (drawPart) {
                        var l = pathSegLen[segCount++];
                        if (accumLength + l > displayedLength) {
                            endAngle = startAngle + delta * (displayedLength - accumLength) / l;
                            breakBuild = true;
                        }
                        accumLength += l;
                    }
                    if (isEllipse && ctx.ellipse) {
                        ctx.ellipse(cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise);
                    }
                    else {
                        ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
                    }
                    if (breakBuild) {
                        break lo;
                    }
                    if (isFirst) {
                        x0 = PathProxy_mathCos(startAngle) * rx + cx;
                        y0 = PathProxy_mathSin(startAngle) * ry + cy;
                    }
                    xi = PathProxy_mathCos(endAngle) * rx + cx;
                    yi = PathProxy_mathSin(endAngle) * ry + cy;
                    break;
                case CMD.R:
                    x0 = xi = d[i];
                    y0 = yi = d[i + 1];
                    x = d[i++];
                    y = d[i++];
                    var width = d[i++];
                    var height = d[i++];
                    if (drawPart) {
                        var l = pathSegLen[segCount++];
                        if (accumLength + l > displayedLength) {
                            var d_1 = displayedLength - accumLength;
                            ctx.moveTo(x, y);
                            ctx.lineTo(x + PathProxy_mathMin(d_1, width), y);
                            d_1 -= width;
                            if (d_1 > 0) {
                                ctx.lineTo(x + width, y + PathProxy_mathMin(d_1, height));
                            }
                            d_1 -= height;
                            if (d_1 > 0) {
                                ctx.lineTo(x + PathProxy_mathMax(width - d_1, 0), y + height);
                            }
                            d_1 -= width;
                            if (d_1 > 0) {
                                ctx.lineTo(x, y + PathProxy_mathMax(height - d_1, 0));
                            }
                            break lo;
                        }
                        accumLength += l;
                    }
                    ctx.rect(x, y, width, height);
                    break;
                case CMD.Z:
                    if (pendingPtDist > 0) {
                        ctx.lineTo(pendingPtX, pendingPtY);
                        pendingPtDist = 0;
                    }
                    if (drawPart) {
                        var l = pathSegLen[segCount++];
                        if (accumLength + l > displayedLength) {
                            var t = (displayedLength - accumLength) / l;
                            ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t);
                            break lo;
                        }
                        accumLength += l;
                    }
                    ctx.closePath();
                    xi = x0;
                    yi = y0;
            }
        }
    };
    PathProxy.CMD = CMD;
    PathProxy.initDefaultProps = (function () {
        var proto = PathProxy.prototype;
        proto._saveData = true;
        proto._needsDash = false;
        proto._dashOffset = 0;
        proto._dashIdx = 0;
        proto._dashSum = 0;
        proto._ux = 0;
        proto._uy = 0;
        proto._pendingPtDist = 0;
        proto._version = 0;
    })();
    return PathProxy;
}());
/* harmony default export */ const core_PathProxy = (PathProxy);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/line.js
function containStroke(x0, y0, x1, y1, lineWidth, x, y) {
    if (lineWidth === 0) {
        return false;
    }
    var _l = lineWidth;
    var _a = 0;
    var _b = x0;
    if ((y > y0 + _l && y > y1 + _l)
        || (y < y0 - _l && y < y1 - _l)
        || (x > x0 + _l && x > x1 + _l)
        || (x < x0 - _l && x < x1 - _l)) {
        return false;
    }
    if (x0 !== x1) {
        _a = (y0 - y1) / (x0 - x1);
        _b = (x0 * y1 - x1 * y0) / (x0 - x1);
    }
    else {
        return Math.abs(x - x0) <= _l / 2;
    }
    var tmp = _a * x - y + _b;
    var _s = tmp * tmp / (_a * _a + 1);
    return _s <= _l / 2 * _l / 2;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/cubic.js

function cubic_containStroke(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
    if (lineWidth === 0) {
        return false;
    }
    var _l = lineWidth;
    if ((y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l)
        || (y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l)
        || (x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l)
        || (x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l)) {
        return false;
    }
    var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null);
    return d <= _l / 2;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/quadratic.js

function quadratic_containStroke(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
    if (lineWidth === 0) {
        return false;
    }
    var _l = lineWidth;
    if ((y > y0 + _l && y > y1 + _l && y > y2 + _l)
        || (y < y0 - _l && y < y1 - _l && y < y2 - _l)
        || (x > x0 + _l && x > x1 + _l && x > x2 + _l)
        || (x < x0 - _l && x < x1 - _l && x < x2 - _l)) {
        return false;
    }
    var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null);
    return d <= _l / 2;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/util.js
var util_PI2 = Math.PI * 2;
function normalizeRadian(angle) {
    angle %= util_PI2;
    if (angle < 0) {
        angle += util_PI2;
    }
    return angle;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/arc.js

var arc_PI2 = Math.PI * 2;
function arc_containStroke(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) {
    if (lineWidth === 0) {
        return false;
    }
    var _l = lineWidth;
    x -= cx;
    y -= cy;
    var d = Math.sqrt(x * x + y * y);
    if ((d - _l > r) || (d + _l < r)) {
        return false;
    }
    if (Math.abs(startAngle - endAngle) % arc_PI2 < 1e-4) {
        return true;
    }
    if (anticlockwise) {
        var tmp = startAngle;
        startAngle = normalizeRadian(endAngle);
        endAngle = normalizeRadian(tmp);
    }
    else {
        startAngle = normalizeRadian(startAngle);
        endAngle = normalizeRadian(endAngle);
    }
    if (startAngle > endAngle) {
        endAngle += arc_PI2;
    }
    var angle = Math.atan2(y, x);
    if (angle < 0) {
        angle += arc_PI2;
    }
    return (angle >= startAngle && angle <= endAngle)
        || (angle + arc_PI2 >= startAngle && angle + arc_PI2 <= endAngle);
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/windingLine.js
function windingLine(x0, y0, x1, y1, x, y) {
    if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
        return 0;
    }
    if (y1 === y0) {
        return 0;
    }
    var t = (y - y0) / (y1 - y0);
    var dir = y1 < y0 ? 1 : -1;
    if (t === 1 || t === 0) {
        dir = y1 < y0 ? 0.5 : -0.5;
    }
    var x_ = t * (x1 - x0) + x0;
    return x_ === x ? Infinity : x_ > x ? dir : 0;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/contain/path.js







var path_CMD = core_PathProxy.CMD;
var path_PI2 = Math.PI * 2;
var path_EPSILON = 1e-4;
function isAroundEqual(a, b) {
    return Math.abs(a - b) < path_EPSILON;
}
var roots = [-1, -1, -1];
var extrema = [-1, -1];
function swapExtrema() {
    var tmp = extrema[0];
    extrema[0] = extrema[1];
    extrema[1] = tmp;
}
function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
    if ((y > y0 && y > y1 && y > y2 && y > y3)
        || (y < y0 && y < y1 && y < y2 && y < y3)) {
        return 0;
    }
    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);
    if (nRoots === 0) {
        return 0;
    }
    else {
        var w = 0;
        var nExtrema = -1;
        var y0_ = void 0;
        var y1_ = void 0;
        for (var i = 0; i < nRoots; i++) {
            var t = roots[i];
            var unit = (t === 0 || t === 1) ? 0.5 : 1;
            var x_ = curve_cubicAt(x0, x1, x2, x3, t);
            if (x_ < x) {
                continue;
            }
            if (nExtrema < 0) {
                nExtrema = curve_cubicExtrema(y0, y1, y2, y3, extrema);
                if (extrema[1] < extrema[0] && nExtrema > 1) {
                    swapExtrema();
                }
                y0_ = curve_cubicAt(y0, y1, y2, y3, extrema[0]);
                if (nExtrema > 1) {
                    y1_ = curve_cubicAt(y0, y1, y2, y3, extrema[1]);
                }
            }
            if (nExtrema === 2) {
                if (t < extrema[0]) {
                    w += y0_ < y0 ? unit : -unit;
                }
                else if (t < extrema[1]) {
                    w += y1_ < y0_ ? unit : -unit;
                }
                else {
                    w += y3 < y1_ ? unit : -unit;
                }
            }
            else {
                if (t < extrema[0]) {
                    w += y0_ < y0 ? unit : -unit;
                }
                else {
                    w += y3 < y0_ ? unit : -unit;
                }
            }
        }
        return w;
    }
}
function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
    if ((y > y0 && y > y1 && y > y2)
        || (y < y0 && y < y1 && y < y2)) {
        return 0;
    }
    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);
    if (nRoots === 0) {
        return 0;
    }
    else {
        var t = curve_quadraticExtremum(y0, y1, y2);
        if (t >= 0 && t <= 1) {
            var w = 0;
            var y_ = curve_quadraticAt(y0, y1, y2, t);
            for (var i = 0; i < nRoots; i++) {
                var unit = (roots[i] === 0 || roots[i] === 1) ? 0.5 : 1;
                var x_ = curve_quadraticAt(x0, x1, x2, roots[i]);
                if (x_ < x) {
                    continue;
                }
                if (roots[i] < t) {
                    w += y_ < y0 ? unit : -unit;
                }
                else {
                    w += y2 < y_ ? unit : -unit;
                }
            }
            return w;
        }
        else {
            var unit = (roots[0] === 0 || roots[0] === 1) ? 0.5 : 1;
            var x_ = curve_quadraticAt(x0, x1, x2, roots[0]);
            if (x_ < x) {
                return 0;
            }
            return y2 < y0 ? unit : -unit;
        }
    }
}
function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) {
    y -= cy;
    if (y > r || y < -r) {
        return 0;
    }
    var tmp = Math.sqrt(r * r - y * y);
    roots[0] = -tmp;
    roots[1] = tmp;
    var dTheta = Math.abs(startAngle - endAngle);
    if (dTheta < 1e-4) {
        return 0;
    }
    if (dTheta >= path_PI2 - 1e-4) {
        startAngle = 0;
        endAngle = path_PI2;
        var dir = anticlockwise ? 1 : -1;
        if (x >= roots[0] + cx && x <= roots[1] + cx) {
            return dir;
        }
        else {
            return 0;
        }
    }
    if (startAngle > endAngle) {
        var tmp_1 = startAngle;
        startAngle = endAngle;
        endAngle = tmp_1;
    }
    if (startAngle < 0) {
        startAngle += path_PI2;
        endAngle += path_PI2;
    }
    var w = 0;
    for (var i = 0; i < 2; i++) {
        var x_ = roots[i];
        if (x_ + cx > x) {
            var angle = Math.atan2(y, x_);
            var dir = anticlockwise ? 1 : -1;
            if (angle < 0) {
                angle = path_PI2 + angle;
            }
            if ((angle >= startAngle && angle <= endAngle)
                || (angle + path_PI2 >= startAngle && angle + path_PI2 <= endAngle)) {
                if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
                    dir = -dir;
                }
                w += dir;
            }
        }
    }
    return w;
}
function containPath(path, lineWidth, isStroke, x, y) {
    var data = path.data;
    var len = path.len();
    var w = 0;
    var xi = 0;
    var yi = 0;
    var x0 = 0;
    var y0 = 0;
    var x1;
    var y1;
    for (var i = 0; i < len;) {
        var cmd = data[i++];
        var isFirst = i === 1;
        if (cmd === path_CMD.M && i > 1) {
            if (!isStroke) {
                w += windingLine(xi, yi, x0, y0, x, y);
            }
        }
        if (isFirst) {
            xi = data[i];
            yi = data[i + 1];
            x0 = xi;
            y0 = yi;
        }
        switch (cmd) {
            case path_CMD.M:
                x0 = data[i++];
                y0 = data[i++];
                xi = x0;
                yi = y0;
                break;
            case path_CMD.L:
                if (isStroke) {
                    if (containStroke(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
                }
                xi = data[i++];
                yi = data[i++];
                break;
            case path_CMD.C:
                if (isStroke) {
                    if (cubic_containStroke(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
                }
                xi = data[i++];
                yi = data[i++];
                break;
            case path_CMD.Q:
                if (isStroke) {
                    if (quadratic_containStroke(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
                }
                xi = data[i++];
                yi = data[i++];
                break;
            case path_CMD.A:
                var cx = data[i++];
                var cy = data[i++];
                var rx = data[i++];
                var ry = data[i++];
                var theta = data[i++];
                var dTheta = data[i++];
                i += 1;
                var anticlockwise = !!(1 - data[i++]);
                x1 = Math.cos(theta) * rx + cx;
                y1 = Math.sin(theta) * ry + cy;
                if (!isFirst) {
                    w += windingLine(xi, yi, x1, y1, x, y);
                }
                else {
                    x0 = x1;
                    y0 = y1;
                }
                var _x = (x - cx) * ry / rx + cx;
                if (isStroke) {
                    if (arc_containStroke(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y);
                }
                xi = Math.cos(theta + dTheta) * rx + cx;
                yi = Math.sin(theta + dTheta) * ry + cy;
                break;
            case path_CMD.R:
                x0 = xi = data[i++];
                y0 = yi = data[i++];
                var width = data[i++];
                var height = data[i++];
                x1 = x0 + width;
                y1 = y0 + height;
                if (isStroke) {
                    if (containStroke(x0, y0, x1, y0, lineWidth, x, y)
                        || containStroke(x1, y0, x1, y1, lineWidth, x, y)
                        || containStroke(x1, y1, x0, y1, lineWidth, x, y)
                        || containStroke(x0, y1, x0, y0, lineWidth, x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingLine(x1, y0, x1, y1, x, y);
                    w += windingLine(x0, y1, x0, y0, x, y);
                }
                break;
            case path_CMD.Z:
                if (isStroke) {
                    if (containStroke(xi, yi, x0, y0, lineWidth, x, y)) {
                        return true;
                    }
                }
                else {
                    w += windingLine(xi, yi, x0, y0, x, y);
                }
                xi = x0;
                yi = y0;
                break;
        }
    }
    if (!isStroke && !isAroundEqual(yi, y0)) {
        w += windingLine(xi, yi, x0, y0, x, y) || 0;
    }
    return w !== 0;
}
function contain(pathProxy, x, y) {
    return containPath(pathProxy, 0, false, x, y);
}
function path_containStroke(pathProxy, lineWidth, x, y) {
    return containPath(pathProxy, lineWidth, true, x, y);
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Path.js








var DEFAULT_PATH_STYLE = util_defaults({
    fill: '#000',
    stroke: null,
    strokePercent: 1,
    fillOpacity: 1,
    strokeOpacity: 1,
    lineDashOffset: 0,
    lineWidth: 1,
    lineCap: 'butt',
    miterLimit: 10,
    strokeNoScale: false,
    strokeFirst: false
}, DEFAULT_COMMON_STYLE);
var DEFAULT_PATH_ANIMATION_PROPS = {
    style: util_defaults({
        fill: true,
        stroke: true,
        strokePercent: true,
        fillOpacity: true,
        strokeOpacity: true,
        lineDashOffset: true,
        lineWidth: true,
        miterLimit: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
};
var pathCopyParams = [
    'x', 'y', 'rotation', 'scaleX', 'scaleY', 'originX', 'originY', 'invisible',
    'culling', 'z', 'z2', 'zlevel', 'parent'
];
var Path = (function (_super) {
    __extends(Path, _super);
    function Path(opts) {
        return _super.call(this, opts) || this;
    }
    Path.prototype.update = function () {
        var _this = this;
        _super.prototype.update.call(this);
        var style = this.style;
        if (style.decal) {
            var decalEl = this._decalEl = this._decalEl || new Path();
            if (decalEl.buildPath === Path.prototype.buildPath) {
                decalEl.buildPath = function (ctx) {
                    _this.buildPath(ctx, _this.shape);
                };
            }
            decalEl.silent = true;
            var decalElStyle = decalEl.style;
            for (var key in style) {
                if (decalElStyle[key] !== style[key]) {
                    decalElStyle[key] = style[key];
                }
            }
            decalElStyle.fill = style.fill ? style.decal : null;
            decalElStyle.decal = null;
            decalElStyle.shadowColor = null;
            style.strokeFirst && (decalElStyle.stroke = null);
            for (var i = 0; i < pathCopyParams.length; ++i) {
                decalEl[pathCopyParams[i]] = this[pathCopyParams[i]];
            }
            decalEl.__dirty |= REDARAW_BIT;
        }
        else if (this._decalEl) {
            this._decalEl = null;
        }
    };
    Path.prototype.getDecalElement = function () {
        return this._decalEl;
    };
    Path.prototype._init = function (props) {
        var keysArr = keys(props);
        this.shape = this.getDefaultShape();
        var defaultStyle = this.getDefaultStyle();
        if (defaultStyle) {
            this.useStyle(defaultStyle);
        }
        for (var i = 0; i < keysArr.length; i++) {
            var key = keysArr[i];
            var value = props[key];
            if (key === 'style') {
                if (!this.style) {
                    this.useStyle(value);
                }
                else {
                    util_extend(this.style, value);
                }
            }
            else if (key === 'shape') {
                util_extend(this.shape, value);
            }
            else {
                _super.prototype.attrKV.call(this, key, value);
            }
        }
        if (!this.style) {
            this.useStyle({});
        }
    };
    Path.prototype.getDefaultStyle = function () {
        return null;
    };
    Path.prototype.getDefaultShape = function () {
        return {};
    };
    Path.prototype.canBeInsideText = function () {
        return this.hasFill();
    };
    Path.prototype.getInsideTextFill = function () {
        var pathFill = this.style.fill;
        if (pathFill !== 'none') {
            if (isString(pathFill)) {
                var fillLum = lum(pathFill, 0);
                if (fillLum > 0.5) {
                    return DARK_LABEL_COLOR;
                }
                else if (fillLum > 0.2) {
                    return LIGHTER_LABEL_COLOR;
                }
                return LIGHT_LABEL_COLOR;
            }
            else if (pathFill) {
                return LIGHT_LABEL_COLOR;
            }
        }
        return DARK_LABEL_COLOR;
    };
    Path.prototype.getInsideTextStroke = function (textFill) {
        var pathFill = this.style.fill;
        if (isString(pathFill)) {
            var zr = this.__zr;
            var isDarkMode = !!(zr && zr.isDarkMode());
            var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD;
            if (isDarkMode === isDarkLabel) {
                return pathFill;
            }
        }
    };
    Path.prototype.buildPath = function (ctx, shapeCfg, inBundle) { };
    Path.prototype.pathUpdated = function () {
        this.__dirty &= ~SHAPE_CHANGED_BIT;
    };
    Path.prototype.createPathProxy = function () {
        this.path = new core_PathProxy(false);
    };
    Path.prototype.hasStroke = function () {
        var style = this.style;
        var stroke = style.stroke;
        return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0));
    };
    Path.prototype.hasFill = function () {
        var style = this.style;
        var fill = style.fill;
        return fill != null && fill !== 'none';
    };
    Path.prototype.getBoundingRect = function () {
        var rect = this._rect;
        var style = this.style;
        var needsUpdateRect = !rect;
        if (needsUpdateRect) {
            var firstInvoke = false;
            if (!this.path) {
                firstInvoke = true;
                this.createPathProxy();
            }
            var path = this.path;
            if (firstInvoke || (this.__dirty & SHAPE_CHANGED_BIT)) {
                path.beginPath();
                this.buildPath(path, this.shape, false);
                this.pathUpdated();
            }
            rect = path.getBoundingRect();
        }
        this._rect = rect;
        if (this.hasStroke() && this.path && this.path.len() > 0) {
            var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());
            if (this.__dirty || needsUpdateRect) {
                rectWithStroke.copy(rect);
                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
                var w = style.lineWidth;
                if (!this.hasFill()) {
                    var strokeContainThreshold = this.strokeContainThreshold;
                    w = Math.max(w, strokeContainThreshold == null ? 4 : strokeContainThreshold);
                }
                if (lineScale > 1e-10) {
                    rectWithStroke.width += w / lineScale;
                    rectWithStroke.height += w / lineScale;
                    rectWithStroke.x -= w / lineScale / 2;
                    rectWithStroke.y -= w / lineScale / 2;
                }
            }
            return rectWithStroke;
        }
        return rect;
    };
    Path.prototype.contain = function (x, y) {
        var localPos = this.transformCoordToLocal(x, y);
        var rect = this.getBoundingRect();
        var style = this.style;
        x = localPos[0];
        y = localPos[1];
        if (rect.contain(x, y)) {
            var pathProxy = this.path;
            if (this.hasStroke()) {
                var lineWidth = style.lineWidth;
                var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
                if (lineScale > 1e-10) {
                    if (!this.hasFill()) {
                        lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
                    }
                    if (path_containStroke(pathProxy, lineWidth / lineScale, x, y)) {
                        return true;
                    }
                }
            }
            if (this.hasFill()) {
                return contain(pathProxy, x, y);
            }
        }
        return false;
    };
    Path.prototype.dirtyShape = function () {
        this.__dirty |= SHAPE_CHANGED_BIT;
        if (this._rect) {
            this._rect = null;
        }
        if (this._decalEl) {
            this._decalEl.dirtyShape();
        }
        this.markRedraw();
    };
    Path.prototype.dirty = function () {
        this.dirtyStyle();
        this.dirtyShape();
    };
    Path.prototype.animateShape = function (loop) {
        return this.animate('shape', loop);
    };
    Path.prototype.updateDuringAnimation = function (targetKey) {
        if (targetKey === 'style') {
            this.dirtyStyle();
        }
        else if (targetKey === 'shape') {
            this.dirtyShape();
        }
        else {
            this.markRedraw();
        }
    };
    Path.prototype.attrKV = function (key, value) {
        if (key === 'shape') {
            this.setShape(value);
        }
        else {
            _super.prototype.attrKV.call(this, key, value);
        }
    };
    Path.prototype.setShape = function (keyOrObj, value) {
        var shape = this.shape;
        if (!shape) {
            shape = this.shape = {};
        }
        if (typeof keyOrObj === 'string') {
            shape[keyOrObj] = value;
        }
        else {
            util_extend(shape, keyOrObj);
        }
        this.dirtyShape();
        return this;
    };
    Path.prototype.shapeChanged = function () {
        return !!(this.__dirty & SHAPE_CHANGED_BIT);
    };
    Path.prototype.createStyle = function (obj) {
        return createObject(DEFAULT_PATH_STYLE, obj);
    };
    Path.prototype._innerSaveToNormal = function (toState) {
        _super.prototype._innerSaveToNormal.call(this, toState);
        var normalState = this._normalState;
        if (toState.shape && !normalState.shape) {
            normalState.shape = util_extend({}, this.shape);
        }
    };
    Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
        _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);
        var needsRestoreToNormal = !(state && keepCurrentStates);
        var targetShape;
        if (state && state.shape) {
            if (transition) {
                if (keepCurrentStates) {
                    targetShape = state.shape;
                }
                else {
                    targetShape = util_extend({}, normalState.shape);
                    util_extend(targetShape, state.shape);
                }
            }
            else {
                targetShape = util_extend({}, keepCurrentStates ? this.shape : normalState.shape);
                util_extend(targetShape, state.shape);
            }
        }
        else if (needsRestoreToNormal) {
            targetShape = normalState.shape;
        }
        if (targetShape) {
            if (transition) {
                this.shape = util_extend({}, this.shape);
                var targetShapePrimaryProps = {};
                var shapeKeys = keys(targetShape);
                for (var i = 0; i < shapeKeys.length; i++) {
                    var key = shapeKeys[i];
                    if (typeof targetShape[key] === 'object') {
                        this.shape[key] = targetShape[key];
                    }
                    else {
                        targetShapePrimaryProps[key] = targetShape[key];
                    }
                }
                this._transitionState(stateName, {
                    shape: targetShapePrimaryProps
                }, animationCfg);
            }
            else {
                this.shape = targetShape;
                this.dirtyShape();
            }
        }
    };
    Path.prototype._mergeStates = function (states) {
        var mergedState = _super.prototype._mergeStates.call(this, states);
        var mergedShape;
        for (var i = 0; i < states.length; i++) {
            var state = states[i];
            if (state.shape) {
                mergedShape = mergedShape || {};
                this._mergeStyle(mergedShape, state.shape);
            }
        }
        if (mergedShape) {
            mergedState.shape = mergedShape;
        }
        return mergedState;
    };
    Path.prototype.getAnimationStyleProps = function () {
        return DEFAULT_PATH_ANIMATION_PROPS;
    };
    Path.prototype.isZeroArea = function () {
        return false;
    };
    Path.extend = function (defaultProps) {
        var Sub = (function (_super) {
            __extends(Sub, _super);
            function Sub(opts) {
                var _this = _super.call(this, opts) || this;
                defaultProps.init && defaultProps.init.call(_this, opts);
                return _this;
            }
            Sub.prototype.getDefaultStyle = function () {
                return clone(defaultProps.style);
            };
            Sub.prototype.getDefaultShape = function () {
                return clone(defaultProps.shape);
            };
            return Sub;
        }(Path));
        for (var key in defaultProps) {
            if (typeof defaultProps[key] === 'function') {
                Sub.prototype[key] = defaultProps[key];
            }
        }
        return Sub;
    };
    Path.initDefaultProps = (function () {
        var pathProto = Path.prototype;
        pathProto.type = 'path';
        pathProto.strokeContainThreshold = 5;
        pathProto.segmentIgnoreThreshold = 0;
        pathProto.subPixelOptimize = false;
        pathProto.autoBatch = false;
        pathProto.__dirty = REDARAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT;
    })();
    return Path;
}(graphic_Displayable));
/* harmony default export */ const graphic_Path = (Path);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/TSpan.js





var DEFAULT_TSPAN_STYLE = util_defaults({
    strokeFirst: true,
    font: DEFAULT_FONT,
    x: 0,
    y: 0,
    textAlign: 'left',
    textBaseline: 'top',
    miterLimit: 2
}, DEFAULT_PATH_STYLE);
var TSpan = (function (_super) {
    __extends(TSpan, _super);
    function TSpan() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    TSpan.prototype.hasStroke = function () {
        var style = this.style;
        var stroke = style.stroke;
        return stroke != null && stroke !== 'none' && style.lineWidth > 0;
    };
    TSpan.prototype.hasFill = function () {
        var style = this.style;
        var fill = style.fill;
        return fill != null && fill !== 'none';
    };
    TSpan.prototype.createStyle = function (obj) {
        return createObject(DEFAULT_TSPAN_STYLE, obj);
    };
    TSpan.prototype.setBoundingRect = function (rect) {
        this._rect = rect;
    };
    TSpan.prototype.getBoundingRect = function () {
        var style = this.style;
        if (!this._rect) {
            var text = style.text;
            text != null ? (text += '') : (text = '');
            var rect = getBoundingRect(text, style.font, style.textAlign, style.textBaseline);
            rect.x += style.x || 0;
            rect.y += style.y || 0;
            if (this.hasStroke()) {
                var w = style.lineWidth;
                rect.x -= w / 2;
                rect.y -= w / 2;
                rect.width += w;
                rect.height += w;
            }
            this._rect = rect;
        }
        return this._rect;
    };
    TSpan.initDefaultProps = (function () {
        var tspanProto = TSpan.prototype;
        tspanProto.dirtyRectTolerance = 10;
    })();
    return TSpan;
}(graphic_Displayable));
TSpan.prototype.type = 'tspan';
/* harmony default export */ const graphic_TSpan = (TSpan);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Image.js




var DEFAULT_IMAGE_STYLE = util_defaults({
    x: 0,
    y: 0
}, DEFAULT_COMMON_STYLE);
var DEFAULT_IMAGE_ANIMATION_PROPS = {
    style: util_defaults({
        x: true,
        y: true,
        width: true,
        height: true,
        sx: true,
        sy: true,
        sWidth: true,
        sHeight: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
};
function isImageLike(source) {
    return !!(source
        && typeof source !== 'string'
        && source.width && source.height);
}
var ZRImage = (function (_super) {
    __extends(ZRImage, _super);
    function ZRImage() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    ZRImage.prototype.createStyle = function (obj) {
        return createObject(DEFAULT_IMAGE_STYLE, obj);
    };
    ZRImage.prototype._getSize = function (dim) {
        var style = this.style;
        var size = style[dim];
        if (size != null) {
            return size;
        }
        var imageSource = isImageLike(style.image)
            ? style.image : this.__image;
        if (!imageSource) {
            return 0;
        }
        var otherDim = dim === 'width' ? 'height' : 'width';
        var otherDimSize = style[otherDim];
        if (otherDimSize == null) {
            return imageSource[dim];
        }
        else {
            return imageSource[dim] / imageSource[otherDim] * otherDimSize;
        }
    };
    ZRImage.prototype.getWidth = function () {
        return this._getSize('width');
    };
    ZRImage.prototype.getHeight = function () {
        return this._getSize('height');
    };
    ZRImage.prototype.getAnimationStyleProps = function () {
        return DEFAULT_IMAGE_ANIMATION_PROPS;
    };
    ZRImage.prototype.getBoundingRect = function () {
        var style = this.style;
        if (!this._rect) {
            this._rect = new core_BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight());
        }
        return this._rect;
    };
    return ZRImage;
}(graphic_Displayable));
ZRImage.prototype.type = 'image';
/* harmony default export */ const graphic_Image = (ZRImage);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/roundRect.js
function buildPath(ctx, shape) {
    var x = shape.x;
    var y = shape.y;
    var width = shape.width;
    var height = shape.height;
    var r = shape.r;
    var r1;
    var r2;
    var r3;
    var r4;
    if (width < 0) {
        x = x + width;
        width = -width;
    }
    if (height < 0) {
        y = y + height;
        height = -height;
    }
    if (typeof r === 'number') {
        r1 = r2 = r3 = r4 = r;
    }
    else if (r instanceof Array) {
        if (r.length === 1) {
            r1 = r2 = r3 = r4 = r[0];
        }
        else if (r.length === 2) {
            r1 = r3 = r[0];
            r2 = r4 = r[1];
        }
        else if (r.length === 3) {
            r1 = r[0];
            r2 = r4 = r[1];
            r3 = r[2];
        }
        else {
            r1 = r[0];
            r2 = r[1];
            r3 = r[2];
            r4 = r[3];
        }
    }
    else {
        r1 = r2 = r3 = r4 = 0;
    }
    var total;
    if (r1 + r2 > width) {
        total = r1 + r2;
        r1 *= width / total;
        r2 *= width / total;
    }
    if (r3 + r4 > width) {
        total = r3 + r4;
        r3 *= width / total;
        r4 *= width / total;
    }
    if (r2 + r3 > height) {
        total = r2 + r3;
        r2 *= height / total;
        r3 *= height / total;
    }
    if (r1 + r4 > height) {
        total = r1 + r4;
        r1 *= height / total;
        r4 *= height / total;
    }
    ctx.moveTo(x + r1, y);
    ctx.lineTo(x + width - r2, y);
    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);
    ctx.lineTo(x + width, y + height - r3);
    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);
    ctx.lineTo(x + r4, y + height);
    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);
    ctx.lineTo(x, y + r1);
    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/subPixelOptimize.js
var round = Math.round;
function subPixelOptimizeLine(outputShape, inputShape, style) {
    if (!inputShape) {
        return;
    }
    var x1 = inputShape.x1;
    var x2 = inputShape.x2;
    var y1 = inputShape.y1;
    var y2 = inputShape.y2;
    outputShape.x1 = x1;
    outputShape.x2 = x2;
    outputShape.y1 = y1;
    outputShape.y2 = y2;
    var lineWidth = style && style.lineWidth;
    if (!lineWidth) {
        return outputShape;
    }
    if (round(x1 * 2) === round(x2 * 2)) {
        outputShape.x1 = outputShape.x2 = subPixelOptimize(x1, lineWidth, true);
    }
    if (round(y1 * 2) === round(y2 * 2)) {
        outputShape.y1 = outputShape.y2 = subPixelOptimize(y1, lineWidth, true);
    }
    return outputShape;
}
function subPixelOptimizeRect(outputShape, inputShape, style) {
    if (!inputShape) {
        return;
    }
    var originX = inputShape.x;
    var originY = inputShape.y;
    var originWidth = inputShape.width;
    var originHeight = inputShape.height;
    outputShape.x = originX;
    outputShape.y = originY;
    outputShape.width = originWidth;
    outputShape.height = originHeight;
    var lineWidth = style && style.lineWidth;
    if (!lineWidth) {
        return outputShape;
    }
    outputShape.x = subPixelOptimize(originX, lineWidth, true);
    outputShape.y = subPixelOptimize(originY, lineWidth, true);
    outputShape.width = Math.max(subPixelOptimize(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1);
    outputShape.height = Math.max(subPixelOptimize(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1);
    return outputShape;
}
function subPixelOptimize(position, lineWidth, positiveOrNegative) {
    if (!lineWidth) {
        return position;
    }
    var doubledPosition = round(position * 2);
    return (doubledPosition + round(lineWidth)) % 2 === 0
        ? doubledPosition / 2
        : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Rect.js




var RectShape = (function () {
    function RectShape() {
        this.x = 0;
        this.y = 0;
        this.width = 0;
        this.height = 0;
    }
    return RectShape;
}());

var subPixelOptimizeOutputShape = {};
var Rect = (function (_super) {
    __extends(Rect, _super);
    function Rect(opts) {
        return _super.call(this, opts) || this;
    }
    Rect.prototype.getDefaultShape = function () {
        return new RectShape();
    };
    Rect.prototype.buildPath = function (ctx, shape) {
        var x;
        var y;
        var width;
        var height;
        if (this.subPixelOptimize) {
            var optimizedShape = subPixelOptimizeRect(subPixelOptimizeOutputShape, shape, this.style);
            x = optimizedShape.x;
            y = optimizedShape.y;
            width = optimizedShape.width;
            height = optimizedShape.height;
            optimizedShape.r = shape.r;
            shape = optimizedShape;
        }
        else {
            x = shape.x;
            y = shape.y;
            width = shape.width;
            height = shape.height;
        }
        if (!shape.r) {
            ctx.rect(x, y, width, height);
        }
        else {
            buildPath(ctx, shape);
        }
    };
    Rect.prototype.isZeroArea = function () {
        return !this.shape.width || !this.shape.height;
    };
    return Rect;
}(graphic_Path));
Rect.prototype.type = 'rect';
/* harmony default export */ const shape_Rect = (Rect);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Text.js










var DEFAULT_RICH_TEXT_COLOR = {
    fill: '#000'
};
var DEFAULT_STROKE_LINE_WIDTH = 2;
var DEFAULT_TEXT_ANIMATION_PROPS = {
    style: util_defaults({
        fill: true,
        stroke: true,
        fillOpacity: true,
        strokeOpacity: true,
        lineWidth: true,
        fontSize: true,
        lineHeight: true,
        width: true,
        height: true,
        textShadowColor: true,
        textShadowBlur: true,
        textShadowOffsetX: true,
        textShadowOffsetY: true,
        backgroundColor: true,
        padding: true,
        borderColor: true,
        borderWidth: true,
        borderRadius: true
    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
};
var ZRText = (function (_super) {
    __extends(ZRText, _super);
    function ZRText(opts) {
        var _this = _super.call(this) || this;
        _this.type = 'text';
        _this._children = [];
        _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR;
        _this.attr(opts);
        return _this;
    }
    ZRText.prototype.childrenRef = function () {
        return this._children;
    };
    ZRText.prototype.update = function () {
        if (this.styleChanged()) {
            this._updateSubTexts();
        }
        for (var i = 0; i < this._children.length; i++) {
            var child = this._children[i];
            child.zlevel = this.zlevel;
            child.z = this.z;
            child.z2 = this.z2;
            child.culling = this.culling;
            child.cursor = this.cursor;
            child.invisible = this.invisible;
        }
        var attachedTransform = this.attachedTransform;
        if (attachedTransform) {
            attachedTransform.updateTransform();
            var m = attachedTransform.transform;
            if (m) {
                this.transform = this.transform || [];
                copy(this.transform, m);
            }
            else {
                this.transform = null;
            }
        }
        else {
            _super.prototype.update.call(this);
        }
    };
    ZRText.prototype.getComputedTransform = function () {
        if (this.__hostTarget) {
            this.__hostTarget.getComputedTransform();
            this.__hostTarget.updateInnerText(true);
        }
        return this.attachedTransform ? this.attachedTransform.getComputedTransform()
            : _super.prototype.getComputedTransform.call(this);
    };
    ZRText.prototype._updateSubTexts = function () {
        this._childCursor = 0;
        normalizeTextStyle(this.style);
        this.style.rich
            ? this._updateRichTexts()
            : this._updatePlainTexts();
        this._children.length = this._childCursor;
        this.styleUpdated();
    };
    ZRText.prototype.addSelfToZr = function (zr) {
        _super.prototype.addSelfToZr.call(this, zr);
        for (var i = 0; i < this._children.length; i++) {
            this._children[i].__zr = zr;
        }
    };
    ZRText.prototype.removeSelfFromZr = function (zr) {
        _super.prototype.removeSelfFromZr.call(this, zr);
        for (var i = 0; i < this._children.length; i++) {
            this._children[i].__zr = null;
        }
    };
    ZRText.prototype.getBoundingRect = function () {
        if (this.styleChanged()) {
            this._updateSubTexts();
        }
        if (!this._rect) {
            var tmpRect = new core_BoundingRect(0, 0, 0, 0);
            var children = this._children;
            var tmpMat = [];
            var rect = null;
            for (var i = 0; i < children.length; i++) {
                var child = children[i];
                var childRect = child.getBoundingRect();
                var transform = child.getLocalTransform(tmpMat);
                if (transform) {
                    tmpRect.copy(childRect);
                    tmpRect.applyTransform(transform);
                    rect = rect || tmpRect.clone();
                    rect.union(tmpRect);
                }
                else {
                    rect = rect || childRect.clone();
                    rect.union(childRect);
                }
            }
            this._rect = rect || tmpRect;
        }
        return this._rect;
    };
    ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) {
        this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR;
    };
    ZRText.prototype.setTextContent = function (textContent) {
        throw new Error('Can\'t attach text on another text');
    };
    ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) {
        if (!sourceStyle) {
            return targetStyle;
        }
        var sourceRich = sourceStyle.rich;
        var targetRich = targetStyle.rich || (sourceRich && {});
        util_extend(targetStyle, sourceStyle);
        if (sourceRich && targetRich) {
            this._mergeRich(targetRich, sourceRich);
            targetStyle.rich = targetRich;
        }
        else if (targetRich) {
            targetStyle.rich = targetRich;
        }
        return targetStyle;
    };
    ZRText.prototype._mergeRich = function (targetRich, sourceRich) {
        var richNames = keys(sourceRich);
        for (var i = 0; i < richNames.length; i++) {
            var richName = richNames[i];
            targetRich[richName] = targetRich[richName] || {};
            util_extend(targetRich[richName], sourceRich[richName]);
        }
    };
    ZRText.prototype.getAnimationStyleProps = function () {
        return DEFAULT_TEXT_ANIMATION_PROPS;
    };
    ZRText.prototype._getOrCreateChild = function (Ctor) {
        var child = this._children[this._childCursor];
        if (!child || !(child instanceof Ctor)) {
            child = new Ctor();
        }
        this._children[this._childCursor++] = child;
        child.__zr = this.__zr;
        child.parent = this;
        return child;
    };
    ZRText.prototype._updatePlainTexts = function () {
        var style = this.style;
        var textFont = style.font || DEFAULT_FONT;
        var textPadding = style.padding;
        var text = getStyleText(style);
        var contentBlock = parsePlainText(text, style);
        var needDrawBg = needDrawBackground(style);
        var bgColorDrawn = !!(style.backgroundColor);
        var outerHeight = contentBlock.outerHeight;
        var textLines = contentBlock.lines;
        var lineHeight = contentBlock.lineHeight;
        var defaultStyle = this._defaultStyle;
        var baseX = style.x || 0;
        var baseY = style.y || 0;
        var textAlign = style.align || defaultStyle.align || 'left';
        var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top';
        var textX = baseX;
        var textY = adjustTextY(baseY, contentBlock.contentHeight, verticalAlign);
        if (needDrawBg || textPadding) {
            var outerWidth_1 = contentBlock.width;
            textPadding && (outerWidth_1 += textPadding[1] + textPadding[3]);
            var boxX = adjustTextX(baseX, outerWidth_1, textAlign);
            var boxY = adjustTextY(baseY, outerHeight, verticalAlign);
            needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth_1, outerHeight);
        }
        textY += lineHeight / 2;
        if (textPadding) {
            textX = getTextXForPadding(baseX, textAlign, textPadding);
            if (verticalAlign === 'top') {
                textY += textPadding[0];
            }
            else if (verticalAlign === 'bottom') {
                textY -= textPadding[2];
            }
        }
        var defaultLineWidth = 0;
        var useDefaultFill = false;
        var textFill = getFill('fill' in style
            ? style.fill
            : (useDefaultFill = true, defaultStyle.fill));
        var textStroke = getStroke('stroke' in style
            ? style.stroke
            : (!bgColorDrawn
                && (!defaultStyle.autoStroke || useDefaultFill))
                ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
                : null);
        var hasShadow = style.textShadowBlur > 0;
        var fixedBoundingRect = style.width != null
            && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll');
        var calculatedLineHeight = contentBlock.calculatedLineHeight;
        for (var i = 0; i < textLines.length; i++) {
            var el = this._getOrCreateChild(graphic_TSpan);
            var subElStyle = el.createStyle();
            el.useStyle(subElStyle);
            subElStyle.text = textLines[i];
            subElStyle.x = textX;
            subElStyle.y = textY;
            if (textAlign) {
                subElStyle.textAlign = textAlign;
            }
            subElStyle.textBaseline = 'middle';
            subElStyle.opacity = style.opacity;
            subElStyle.strokeFirst = true;
            if (hasShadow) {
                subElStyle.shadowBlur = style.textShadowBlur || 0;
                subElStyle.shadowColor = style.textShadowColor || 'transparent';
                subElStyle.shadowOffsetX = style.textShadowOffsetX || 0;
                subElStyle.shadowOffsetY = style.textShadowOffsetY || 0;
            }
            if (textStroke) {
                subElStyle.stroke = textStroke;
                subElStyle.lineWidth = style.lineWidth || defaultLineWidth;
                subElStyle.lineDash = style.lineDash;
                subElStyle.lineDashOffset = style.lineDashOffset || 0;
            }
            if (textFill) {
                subElStyle.fill = textFill;
            }
            subElStyle.font = textFont;
            textY += lineHeight;
            if (fixedBoundingRect) {
                el.setBoundingRect(new core_BoundingRect(adjustTextX(subElStyle.x, style.width, subElStyle.textAlign), adjustTextY(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline), style.width, calculatedLineHeight));
            }
        }
    };
    ZRText.prototype._updateRichTexts = function () {
        var style = this.style;
        var text = getStyleText(style);
        var contentBlock = parseRichText(text, style);
        var contentWidth = contentBlock.width;
        var outerWidth = contentBlock.outerWidth;
        var outerHeight = contentBlock.outerHeight;
        var textPadding = style.padding;
        var baseX = style.x || 0;
        var baseY = style.y || 0;
        var defaultStyle = this._defaultStyle;
        var textAlign = style.align || defaultStyle.align;
        var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign;
        var boxX = adjustTextX(baseX, outerWidth, textAlign);
        var boxY = adjustTextY(baseY, outerHeight, verticalAlign);
        var xLeft = boxX;
        var lineTop = boxY;
        if (textPadding) {
            xLeft += textPadding[3];
            lineTop += textPadding[0];
        }
        var xRight = xLeft + contentWidth;
        if (needDrawBackground(style)) {
            this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight);
        }
        var bgColorDrawn = !!(style.backgroundColor);
        for (var i = 0; i < contentBlock.lines.length; i++) {
            var line = contentBlock.lines[i];
            var tokens = line.tokens;
            var tokenCount = tokens.length;
            var lineHeight = line.lineHeight;
            var remainedWidth = line.width;
            var leftIndex = 0;
            var lineXLeft = xLeft;
            var lineXRight = xRight;
            var rightIndex = tokenCount - 1;
            var token = void 0;
            while (leftIndex < tokenCount
                && (token = tokens[leftIndex], !token.align || token.align === 'left')) {
                this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn);
                remainedWidth -= token.width;
                lineXLeft += token.width;
                leftIndex++;
            }
            while (rightIndex >= 0
                && (token = tokens[rightIndex], token.align === 'right')) {
                this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn);
                remainedWidth -= token.width;
                lineXRight -= token.width;
                rightIndex--;
            }
            lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2;
            while (leftIndex <= rightIndex) {
                token = tokens[leftIndex];
                this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn);
                lineXLeft += token.width;
                leftIndex++;
            }
            lineTop += lineHeight;
        }
    };
    ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) {
        var tokenStyle = style.rich[token.styleName] || {};
        tokenStyle.text = token.text;
        var verticalAlign = token.verticalAlign;
        var y = lineTop + lineHeight / 2;
        if (verticalAlign === 'top') {
            y = lineTop + token.height / 2;
        }
        else if (verticalAlign === 'bottom') {
            y = lineTop + lineHeight - token.height / 2;
        }
        var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle);
        needDrawBg && this._renderBackground(tokenStyle, style, textAlign === 'right'
            ? x - token.width
            : textAlign === 'center'
                ? x - token.width / 2
                : x, y - token.height / 2, token.width, token.height);
        var bgColorDrawn = !!tokenStyle.backgroundColor;
        var textPadding = token.textPadding;
        if (textPadding) {
            x = getTextXForPadding(x, textAlign, textPadding);
            y -= token.height / 2 - textPadding[0] - token.innerHeight / 2;
        }
        var el = this._getOrCreateChild(graphic_TSpan);
        var subElStyle = el.createStyle();
        el.useStyle(subElStyle);
        var defaultStyle = this._defaultStyle;
        var useDefaultFill = false;
        var defaultLineWidth = 0;
        var textFill = getStroke('fill' in tokenStyle ? tokenStyle.fill
            : 'fill' in style ? style.fill
                : (useDefaultFill = true, defaultStyle.fill));
        var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke
            : 'stroke' in style ? style.stroke
                : (!bgColorDrawn
                    && !parentBgColorDrawn
                    && (!defaultStyle.autoStroke || useDefaultFill)) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke)
                    : null);
        var hasShadow = tokenStyle.textShadowBlur > 0
            || style.textShadowBlur > 0;
        subElStyle.text = token.text;
        subElStyle.x = x;
        subElStyle.y = y;
        if (hasShadow) {
            subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0;
            subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent';
            subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0;
            subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0;
        }
        subElStyle.textAlign = textAlign;
        subElStyle.textBaseline = 'middle';
        subElStyle.font = token.font || DEFAULT_FONT;
        subElStyle.opacity = retrieve3(tokenStyle.opacity, style.opacity, 1);
        if (textStroke) {
            subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth);
            subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash);
            subElStyle.lineDashOffset = style.lineDashOffset || 0;
            subElStyle.stroke = textStroke;
        }
        if (textFill) {
            subElStyle.fill = textFill;
        }
        var textWidth = token.contentWidth;
        var textHeight = token.contentHeight;
        el.setBoundingRect(new core_BoundingRect(adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign), adjustTextY(subElStyle.y, textHeight, subElStyle.textBaseline), textWidth, textHeight));
    };
    ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) {
        var textBackgroundColor = style.backgroundColor;
        var textBorderWidth = style.borderWidth;
        var textBorderColor = style.borderColor;
        var isImageBg = textBackgroundColor && textBackgroundColor.image;
        var isPlainOrGradientBg = textBackgroundColor && !isImageBg;
        var textBorderRadius = style.borderRadius;
        var self = this;
        var rectEl;
        var imgEl;
        if (isPlainOrGradientBg || (textBorderWidth && textBorderColor)) {
            rectEl = this._getOrCreateChild(shape_Rect);
            rectEl.useStyle(rectEl.createStyle());
            rectEl.style.fill = null;
            var rectShape = rectEl.shape;
            rectShape.x = x;
            rectShape.y = y;
            rectShape.width = width;
            rectShape.height = height;
            rectShape.r = textBorderRadius;
            rectEl.dirtyShape();
        }
        if (isPlainOrGradientBg) {
            var rectStyle = rectEl.style;
            rectStyle.fill = textBackgroundColor || null;
            rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1);
        }
        else if (isImageBg) {
            imgEl = this._getOrCreateChild(graphic_Image);
            imgEl.onload = function () {
                self.dirtyStyle();
            };
            var imgStyle = imgEl.style;
            imgStyle.image = textBackgroundColor.image;
            imgStyle.x = x;
            imgStyle.y = y;
            imgStyle.width = width;
            imgStyle.height = height;
        }
        if (textBorderWidth && textBorderColor) {
            var rectStyle = rectEl.style;
            rectStyle.lineWidth = textBorderWidth;
            rectStyle.stroke = textBorderColor;
            rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1);
            rectStyle.lineDash = style.borderDash;
            rectStyle.lineDashOffset = style.borderDashOffset || 0;
            rectEl.strokeContainThreshold = 0;
            if (rectEl.hasFill() && rectEl.hasStroke()) {
                rectStyle.strokeFirst = true;
                rectStyle.lineWidth *= 2;
            }
        }
        var commonStyle = (rectEl || imgEl).style;
        commonStyle.shadowBlur = style.shadowBlur || 0;
        commonStyle.shadowColor = style.shadowColor || 'transparent';
        commonStyle.shadowOffsetX = style.shadowOffsetX || 0;
        commonStyle.shadowOffsetY = style.shadowOffsetY || 0;
        commonStyle.opacity = retrieve3(style.opacity, topStyle.opacity, 1);
    };
    ZRText.makeFont = function (style) {
        var font = '';
        if (style.fontSize || style.fontFamily || style.fontWeight) {
            var fontSize = '';
            if (typeof style.fontSize === 'string'
                && (style.fontSize.indexOf('px') !== -1
                    || style.fontSize.indexOf('rem') !== -1
                    || style.fontSize.indexOf('em') !== -1)) {
                fontSize = style.fontSize;
            }
            else if (!isNaN(+style.fontSize)) {
                fontSize = style.fontSize + 'px';
            }
            else {
                fontSize = '12px';
            }
            font = [
                style.fontStyle,
                style.fontWeight,
                fontSize,
                style.fontFamily || 'sans-serif'
            ].join(' ');
        }
        return font && trim(font) || style.textFont || style.font;
    };
    return ZRText;
}(graphic_Displayable));
var VALID_TEXT_ALIGN = { left: true, right: 1, center: 1 };
var VALID_TEXT_VERTICAL_ALIGN = { top: 1, bottom: 1, middle: 1 };
function normalizeTextStyle(style) {
    normalizeStyle(style);
    each(style.rich, normalizeStyle);
    return style;
}
function normalizeStyle(style) {
    if (style) {
        style.font = ZRText.makeFont(style);
        var textAlign = style.align;
        textAlign === 'middle' && (textAlign = 'center');
        style.align = (textAlign == null || VALID_TEXT_ALIGN[textAlign]) ? textAlign : 'left';
        var verticalAlign = style.verticalAlign;
        verticalAlign === 'center' && (verticalAlign = 'middle');
        style.verticalAlign = (verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign]) ? verticalAlign : 'top';
        var textPadding = style.padding;
        if (textPadding) {
            style.padding = normalizeCssArray(style.padding);
        }
    }
}
function getStroke(stroke, lineWidth) {
    return (stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none')
        ? null
        : (stroke.image || stroke.colorStops)
            ? '#000'
            : stroke;
}
function getFill(fill) {
    return (fill == null || fill === 'none')
        ? null
        : (fill.image || fill.colorStops)
            ? '#000'
            : fill;
}
function getTextXForPadding(x, textAlign, textPadding) {
    return textAlign === 'right'
        ? (x - textPadding[1])
        : textAlign === 'center'
            ? (x + textPadding[3] / 2 - textPadding[1] / 2)
            : (x + textPadding[3]);
}
function getStyleText(style) {
    var text = style.text;
    text != null && (text += '');
    return text;
}
function needDrawBackground(style) {
    return !!(style.backgroundColor
        || (style.borderWidth && style.borderColor));
}
/* harmony default export */ const Text = (ZRText);

;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/number.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* A third-party license is embeded for some of the code in this file:
* The method "quantile" was copied from "d3.js".
* (See more details in the comment of the method below.)
* The use of the source code of this file is also subject to the terms
* and consitions of the license of "d3.js" (BSD-3Clause, see
* </licenses/LICENSE-d3>).
*/

var RADIAN_EPSILON = 1e-4; // Although chrome already enlarge this number to 100 for `toFixed`, but
// we sill follow the spec for compatibility.

var ROUND_SUPPORTED_PRECISION_MAX = 20;

function _trim(str) {
  return str.replace(/^\s+|\s+$/g, '');
}
/**
 * Linear mapping a value from domain to range
 * @param  val
 * @param  domain Domain extent domain[0] can be bigger than domain[1]
 * @param  range  Range extent range[0] can be bigger than range[1]
 * @param  clamp Default to be false
 */


function linearMap(val, domain, range, clamp) {
  var d0 = domain[0];
  var d1 = domain[1];
  var r0 = range[0];
  var r1 = range[1];
  var subDomain = d1 - d0;
  var subRange = r1 - r0;

  if (subDomain === 0) {
    return subRange === 0 ? r0 : (r0 + r1) / 2;
  } // Avoid accuracy problem in edge, such as
  // 146.39 - 62.83 === 83.55999999999999.
  // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError
  // It is a little verbose for efficiency considering this method
  // is a hotspot.


  if (clamp) {
    if (subDomain > 0) {
      if (val <= d0) {
        return r0;
      } else if (val >= d1) {
        return r1;
      }
    } else {
      if (val >= d0) {
        return r0;
      } else if (val <= d1) {
        return r1;
      }
    }
  } else {
    if (val === d0) {
      return r0;
    }

    if (val === d1) {
      return r1;
    }
  }

  return (val - d0) / subDomain * subRange + r0;
}
/**
 * Convert a percent string to absolute number.
 * Returns NaN if percent is not a valid string or number
 */

function number_parsePercent(percent, all) {
  switch (percent) {
    case 'center':
    case 'middle':
      percent = '50%';
      break;

    case 'left':
    case 'top':
      percent = '0%';
      break;

    case 'right':
    case 'bottom':
      percent = '100%';
      break;
  }

  if (typeof percent === 'string') {
    if (_trim(percent).match(/%$/)) {
      return parseFloat(percent) / 100 * all;
    }

    return parseFloat(percent);
  }

  return percent == null ? NaN : +percent;
}
function number_round(x, precision, returnStr) {
  if (precision == null) {
    precision = 10;
  } // Avoid range error


  precision = Math.min(Math.max(0, precision), ROUND_SUPPORTED_PRECISION_MAX); // PENDING: 1.005.toFixed(2) is '1.00' rather than '1.01'

  x = (+x).toFixed(precision);
  return returnStr ? x : +x;
}
/**
 * Inplacd asc sort arr.
 * The input arr will be modified.
 */

function asc(arr) {
  arr.sort(function (a, b) {
    return a - b;
  });
  return arr;
}
/**
 * Get precision.
 */

function getPrecision(val) {
  val = +val;

  if (isNaN(val)) {
    return 0;
  } // It is much faster than methods converting number to string as follows
  //      let tmp = val.toString();
  //      return tmp.length - 1 - tmp.indexOf('.');
  // especially when precision is low
  // Notice:
  // (1) If the loop count is over about 20, it is slower than `getPrecisionSafe`.
  //     (see https://jsbench.me/2vkpcekkvw/1)
  // (2) If the val is less than for example 1e-15, the result may be incorrect.
  //     (see test/ut/spec/util/number.test.ts `getPrecision_equal_random`)


  if (val > 1e-14) {
    var e = 1;

    for (var i = 0; i < 15; i++, e *= 10) {
      if (Math.round(val * e) / e === val) {
        return i;
      }
    }
  }

  return getPrecisionSafe(val);
}
/**
 * Get precision with slow but safe method
 */

function getPrecisionSafe(val) {
  // toLowerCase for: '3.4E-12'
  var str = val.toString().toLowerCase(); // Consider scientific notation: '3.4e-12' '3.4e+12'

  var eIndex = str.indexOf('e');
  var exp = eIndex > 0 ? +str.slice(eIndex + 1) : 0;
  var significandPartLen = eIndex > 0 ? eIndex : str.length;
  var dotIndex = str.indexOf('.');
  var decimalPartLen = dotIndex < 0 ? 0 : significandPartLen - 1 - dotIndex;
  return Math.max(0, decimalPartLen - exp);
}
/**
 * Minimal dicernible data precisioin according to a single pixel.
 */

function getPixelPrecision(dataExtent, pixelExtent) {
  var log = Math.log;
  var LN10 = Math.LN10;
  var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);
  var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10); // toFixed() digits argument must be between 0 and 20.

  var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);
  return !isFinite(precision) ? 20 : precision;
}
/**
 * Get a data of given precision, assuring the sum of percentages
 * in valueList is 1.
 * The largest remainer method is used.
 * https://en.wikipedia.org/wiki/Largest_remainder_method
 *
 * @param valueList a list of all data
 * @param idx index of the data to be processed in valueList
 * @param precision integer number showing digits of precision
 * @return percent ranging from 0 to 100
 */

function getPercentWithPrecision(valueList, idx, precision) {
  if (!valueList[idx]) {
    return 0;
  }

  var sum = reduce(valueList, function (acc, val) {
    return acc + (isNaN(val) ? 0 : val);
  }, 0);

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

  var digits = Math.pow(10, precision);
  var votesPerQuota = map(valueList, function (val) {
    return (isNaN(val) ? 0 : val) / sum * digits * 100;
  });
  var targetSeats = digits * 100;
  var seats = map(votesPerQuota, function (votes) {
    // Assign automatic seats.
    return Math.floor(votes);
  });
  var currentSum = reduce(seats, function (acc, val) {
    return acc + val;
  }, 0);
  var remainder = map(votesPerQuota, function (votes, idx) {
    return votes - seats[idx];
  }); // Has remainding votes.

  while (currentSum < targetSeats) {
    // Find next largest remainder.
    var max = Number.NEGATIVE_INFINITY;
    var maxId = null;

    for (var i = 0, len = remainder.length; i < len; ++i) {
      if (remainder[i] > max) {
        max = remainder[i];
        maxId = i;
      }
    } // Add a vote to max remainder.


    ++seats[maxId];
    remainder[maxId] = 0;
    ++currentSum;
  }

  return seats[idx] / digits;
}
/**
 * Solve the floating point adding problem like 0.1 + 0.2 === 0.30000000000000004
 * See <http://0.30000000000000004.com/>
 */

function addSafe(val0, val1) {
  var maxPrecision = Math.max(getPrecision(val0), getPrecision(val1)); // const multiplier = Math.pow(10, maxPrecision);
  // return (Math.round(val0 * multiplier) + Math.round(val1 * multiplier)) / multiplier;

  var sum = val0 + val1; // // PENDING: support more?

  return maxPrecision > ROUND_SUPPORTED_PRECISION_MAX ? sum : number_round(sum, maxPrecision);
} // Number.MAX_SAFE_INTEGER, ie do not support.

var MAX_SAFE_INTEGER = 9007199254740991;
/**
 * To 0 - 2 * PI, considering negative radian.
 */

function remRadian(radian) {
  var pi2 = Math.PI * 2;
  return (radian % pi2 + pi2) % pi2;
}
/**
 * @param {type} radian
 * @return {boolean}
 */

function isRadianAroundZero(val) {
  return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;
} // eslint-disable-next-line

var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line

/**
 * @param value valid type: number | string | Date, otherwise return `new Date(NaN)`
 *   These values can be accepted:
 *   + An instance of Date, represent a time in its own time zone.
 *   + Or string in a subset of ISO 8601, only including:
 *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',
 *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',
 *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',
 *     all of which will be treated as local time if time zone is not specified
 *     (see <https://momentjs.com/>).
 *   + Or other string format, including (all of which will be treated as loacal time):
 *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',
 *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'
 *   + a timestamp, which represent a time in UTC.
 * @return date Never be null/undefined. If invalid, return `new Date(NaN)`.
 */

function parseDate(value) {
  if (value instanceof Date) {
    return value;
  } else if (typeof value === 'string') {
    // Different browsers parse date in different way, so we parse it manually.
    // Some other issues:
    // new Date('1970-01-01') is UTC,
    // new Date('1970/01/01') and new Date('1970-1-01') is local.
    // See issue #3623
    var match = TIME_REG.exec(value);

    if (!match) {
      // return Invalid Date.
      return new Date(NaN);
    } // Use local time when no timezone offset specifed.


    if (!match[8]) {
      // match[n] can only be string or undefined.
      // But take care of '12' + 1 => '121'.
      return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, +match[7] || 0);
    } // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,
    // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).
    // For example, system timezone is set as "Time Zone: America/Toronto",
    // then these code will get different result:
    // `new Date(1478411999999).getTimezoneOffset();  // get 240`
    // `new Date(1478412000000).getTimezoneOffset();  // get 300`
    // So we should not use `new Date`, but use `Date.UTC`.
    else {
        var hour = +match[4] || 0;

        if (match[8].toUpperCase() !== 'Z') {
          hour -= +match[8].slice(0, 3);
        }

        return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, +match[7] || 0));
      }
  } else if (value == null) {
    return new Date(NaN);
  }

  return new Date(Math.round(value));
}
/**
 * Quantity of a number. e.g. 0.1, 1, 10, 100
 *
 * @param val
 * @return
 */

function quantity(val) {
  return Math.pow(10, quantityExponent(val));
}
/**
 * Exponent of the quantity of a number
 * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3
 *
 * @param val non-negative value
 * @return
 */

function quantityExponent(val) {
  if (val === 0) {
    return 0;
  }

  var exp = Math.floor(Math.log(val) / Math.LN10);
  /**
   * exp is expected to be the rounded-down result of the base-10 log of val.
   * But due to the precision loss with Math.log(val), we need to restore it
   * using 10^exp to make sure we can get val back from exp. #11249
   */

  if (val / Math.pow(10, exp) >= 10) {
    exp++;
  }

  return exp;
}
/**
 * find a “nice” number approximately equal to x. Round the number if round = true,
 * take ceiling if round = false. The primary observation is that the “nicest”
 * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.
 *
 * See "Nice Numbers for Graph Labels" of Graphic Gems.
 *
 * @param  val Non-negative value.
 * @param  round
 * @return Niced number
 */

function nice(val, round) {
  var exponent = quantityExponent(val);
  var exp10 = Math.pow(10, exponent);
  var f = val / exp10; // 1 <= f < 10

  var nf;

  if (round) {
    if (f < 1.5) {
      nf = 1;
    } else if (f < 2.5) {
      nf = 2;
    } else if (f < 4) {
      nf = 3;
    } else if (f < 7) {
      nf = 5;
    } else {
      nf = 10;
    }
  } else {
    if (f < 1) {
      nf = 1;
    } else if (f < 2) {
      nf = 2;
    } else if (f < 3) {
      nf = 3;
    } else if (f < 5) {
      nf = 5;
    } else {
      nf = 10;
    }
  }

  val = nf * exp10; // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).
  // 20 is the uppper bound of toFixed.

  return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;
}
/**
 * This code was copied from "d3.js"
 * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.
 * See the license statement at the head of this file.
 * @param ascArr
 */

function quantile(ascArr, p) {
  var H = (ascArr.length - 1) * p + 1;
  var h = Math.floor(H);
  var v = +ascArr[h - 1];
  var e = H - h;
  return e ? v + e * (ascArr[h] - v) : v;
}
/**
 * Order intervals asc, and split them when overlap.
 * expect(numberUtil.reformIntervals([
 *     {interval: [18, 62], close: [1, 1]},
 *     {interval: [-Infinity, -70], close: [0, 0]},
 *     {interval: [-70, -26], close: [1, 1]},
 *     {interval: [-26, 18], close: [1, 1]},
 *     {interval: [62, 150], close: [1, 1]},
 *     {interval: [106, 150], close: [1, 1]},
 *     {interval: [150, Infinity], close: [0, 0]}
 * ])).toEqual([
 *     {interval: [-Infinity, -70], close: [0, 0]},
 *     {interval: [-70, -26], close: [1, 1]},
 *     {interval: [-26, 18], close: [0, 1]},
 *     {interval: [18, 62], close: [0, 1]},
 *     {interval: [62, 150], close: [0, 1]},
 *     {interval: [150, Infinity], close: [0, 0]}
 * ]);
 * @param list, where `close` mean open or close
 *        of the interval, and Infinity can be used.
 * @return The origin list, which has been reformed.
 */

function reformIntervals(list) {
  list.sort(function (a, b) {
    return littleThan(a, b, 0) ? -1 : 1;
  });
  var curr = -Infinity;
  var currClose = 1;

  for (var i = 0; i < list.length;) {
    var interval = list[i].interval;
    var close_1 = list[i].close;

    for (var lg = 0; lg < 2; lg++) {
      if (interval[lg] <= curr) {
        interval[lg] = curr;
        close_1[lg] = !lg ? 1 - currClose : 1;
      }

      curr = interval[lg];
      currClose = close_1[lg];
    }

    if (interval[0] === interval[1] && close_1[0] * close_1[1] !== 1) {
      list.splice(i, 1);
    } else {
      i++;
    }
  }

  return list;

  function littleThan(a, b, lg) {
    return a.interval[lg] < b.interval[lg] || a.interval[lg] === b.interval[lg] && (a.close[lg] - b.close[lg] === (!lg ? 1 : -1) || !lg && littleThan(a, b, 1));
  }
}
/**
 * [Numberic is defined as]:
 *     `parseFloat(val) == val`
 * For example:
 * numeric:
 *     typeof number except NaN, '-123', '123', '2e3', '-2e3', '011', 'Infinity', Infinity,
 *     and they rounded by white-spaces or line-terminal like ' -123 \n ' (see es spec)
 * not-numeric:
 *     null, undefined, [], {}, true, false, 'NaN', NaN, '123ab',
 *     empty string, string with only white-spaces or line-terminal (see es spec),
 *     0x12, '0x12', '-0x12', 012, '012', '-012',
 *     non-string, ...
 *
 * @test See full test cases in `test/ut/spec/util/number.js`.
 * @return Must be a typeof number. If not numeric, return NaN.
 */

function numericToNumber(val) {
  var valFloat = parseFloat(val);
  return valFloat == val // eslint-disable-line eqeqeq
  && (valFloat !== 0 || typeof val !== 'string' || val.indexOf('x') <= 0) // For case ' 0x0 '.
  ? valFloat : NaN;
}
/**
 * Definition of "numeric": see `numericToNumber`.
 */

function isNumeric(val) {
  return !isNaN(numericToNumber(val));
}
/**
 * Use random base to prevent users hard code depending on
 * this auto generated marker id.
 * @return An positive integer.
 */

function getRandomIdBase() {
  return Math.round(Math.random() * 9);
}
/**
 * Get the greatest common dividor
 *
 * @param {number} a one number
 * @param {number} b the other number
 */

function getGreatestCommonDividor(a, b) {
  if (b === 0) {
    return a;
  }

  return getGreatestCommonDividor(b, a % b);
}
/**
 * Get the least common multiple
 *
 * @param {number} a one number
 * @param {number} b the other number
 */

function getLeastCommonMultiple(a, b) {
  if (a == null) {
    return b;
  }

  if (b == null) {
    return a;
  }

  return a * b / getGreatestCommonDividor(a, b);
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/log.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var ECHARTS_PREFIX = '[ECharts] ';
var storedLogs = {};
var hasConsole = typeof console !== 'undefined' // eslint-disable-next-line
&& console.warn && console.log;
function log(str) {
  if (hasConsole) {
    // eslint-disable-next-line
    console.log(ECHARTS_PREFIX + str);
  }
}
function warn(str) {
  if (hasConsole) {
    console.warn(ECHARTS_PREFIX + str);
  }
}
function error(str) {
  if (hasConsole) {
    console.error(ECHARTS_PREFIX + str);
  }
}
function deprecateLog(str) {
  if (true) {
    if (storedLogs[str]) {
      // Not display duplicate message.
      return;
    }

    if (hasConsole) {
      storedLogs[str] = true;
      console.warn(ECHARTS_PREFIX + 'DEPRECATED: ' + str);
    }
  }
}
function deprecateReplaceLog(oldOpt, newOpt, scope) {
  if (true) {
    deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated, use " + newOpt + " instead."));
  }
}
function consoleLog() {
  var args = [];

  for (var _i = 0; _i < arguments.length; _i++) {
    args[_i] = arguments[_i];
  }

  if (true) {
    /* eslint-disable no-console */
    if (typeof console !== 'undefined' && console.log) {
      console.log.apply(console, args);
    }
    /* eslint-enable no-console */

  }
}
/**
 * If in __DEV__ environment, get console printable message for users hint.
 * Parameters are separated by ' '.
 * @usuage
 * makePrintable('This is an error on', someVar, someObj);
 *
 * @param hintInfo anything about the current execution context to hint users.
 * @throws Error
 */

function makePrintable() {
  var hintInfo = [];

  for (var _i = 0; _i < arguments.length; _i++) {
    hintInfo[_i] = arguments[_i];
  }

  var msg = '';

  if (true) {
    // Fuzzy stringify for print.
    // This code only exist in dev environment.
    var makePrintableStringIfPossible_1 = function (val) {
      return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : null;
    };

    msg = map(hintInfo, function (arg) {
      if (isString(arg)) {
        // Print without quotation mark for some statement.
        return arg;
      } else {
        var printableStr = makePrintableStringIfPossible_1(arg);

        if (printableStr != null) {
          return printableStr;
        } else if (typeof JSON !== 'undefined' && JSON.stringify) {
          try {
            return JSON.stringify(arg, function (n, val) {
              var printableStr = makePrintableStringIfPossible_1(val);
              return printableStr == null ? val : printableStr;
            }); // In most cases the info object is small, so do not line break.
          } catch (err) {
            return '?';
          }
        } else {
          return '?';
        }
      }
    }).join(' ');
  }

  return msg;
}
/**
 * @throws Error
 */

function throwError(msg) {
  throw new Error(msg);
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/model.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/





/**
 * Make the name displayable. But we should
 * make sure it is not duplicated with user
 * specified name, so use '\0';
 */

var DUMMY_COMPONENT_NAME_PREFIX = 'series\0';
var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0';
/**
 * If value is not array, then translate it to array.
 * @param  {*} value
 * @return {Array} [value] or value
 */

function normalizeToArray(value) {
  return value instanceof Array ? value : value == null ? [] : [value];
}
/**
 * Sync default option between normal and emphasis like `position` and `show`
 * In case some one will write code like
 *     label: {
 *          show: false,
 *          position: 'outside',
 *          fontSize: 18
 *     },
 *     emphasis: {
 *          label: { show: true }
 *     }
 */

function defaultEmphasis(opt, key, subOpts) {
  // Caution: performance sensitive.
  if (opt) {
    opt[key] = opt[key] || {};
    opt.emphasis = opt.emphasis || {};
    opt.emphasis[key] = opt.emphasis[key] || {}; // Default emphasis option from normal

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

      if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) {
        opt.emphasis[key][subOptName] = opt[key][subOptName];
      }
    }
  }
}
var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding']; // modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([
//     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',
//     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',
//     // FIXME: deprecated, check and remove it.
//     'textStyle'
// ]);

/**
 * The method do not ensure performance.
 * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
 * This helper method retieves value from data.
 */

function getDataItemValue(dataItem) {
  return isObject(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem;
}
/**
 * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
 * This helper method determine if dataItem has extra option besides value
 */

function isDataItemOption(dataItem) {
  return isObject(dataItem) && !(dataItem instanceof Array); // // markLine data can be array
  // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));
}
;
/**
 * Mapping to existings for merge.
 *
 * Mode "normalMege":
 *     The mapping result (merge result) will keep the order of the existing
 *     component, rather than the order of new option. Because we should ensure
 *     some specified index reference (like xAxisIndex) keep work.
 *     And in most cases, "merge option" is used to update partial option but not
 *     be expected to change the order.
 *
 * Mode "replaceMege":
 *     (1) Only the id mapped components will be merged.
 *     (2) Other existing components (except internal compoonets) will be removed.
 *     (3) Other new options will be used to create new component.
 *     (4) The index of the existing compoents will not be modified.
 *     That means their might be "hole" after the removal.
 *     The new components are created first at those available index.
 *
 * Mode "replaceAll":
 *     This mode try to support that reproduce an echarts instance from another
 *     echarts instance (via `getOption`) in some simple cases.
 *     In this senario, the `result` index are exactly the consistent with the `newCmptOptions`,
 *     which ensures the compoennt index referring (like `xAxisIndex: ?`) corrent. That is,
 *     the "hole" in `newCmptOptions` will also be kept.
 *     On the contrary, other modes try best to eliminate holes.
 *     PENDING: This is an experimental mode yet.
 *
 * @return See the comment of <MappingResult>.
 */

function mappingToExists(existings, newCmptOptions, mode) {
  var isNormalMergeMode = mode === 'normalMerge';
  var isReplaceMergeMode = mode === 'replaceMerge';
  var isReplaceAllMode = mode === 'replaceAll';
  existings = existings || [];
  newCmptOptions = (newCmptOptions || []).slice();
  var existingIdIdxMap = createHashMap(); // Validate id and name on user input option.

  each(newCmptOptions, function (cmptOption, index) {
    if (!isObject(cmptOption)) {
      newCmptOptions[index] = null;
      return;
    }

    if (true) {
      // There is some legacy case that name is set as `false`.
      // But should work normally rather than throw error.
      if (cmptOption.id != null && !isValidIdOrName(cmptOption.id)) {
        warnInvalidateIdOrName(cmptOption.id);
      }

      if (cmptOption.name != null && !isValidIdOrName(cmptOption.name)) {
        warnInvalidateIdOrName(cmptOption.name);
      }
    }
  });
  var result = prepareResult(existings, existingIdIdxMap, mode);

  if (isNormalMergeMode || isReplaceMergeMode) {
    mappingById(result, existings, existingIdIdxMap, newCmptOptions);
  }

  if (isNormalMergeMode) {
    mappingByName(result, newCmptOptions);
  }

  if (isNormalMergeMode || isReplaceMergeMode) {
    mappingByIndex(result, newCmptOptions, isReplaceMergeMode);
  } else if (isReplaceAllMode) {
    mappingInReplaceAllMode(result, newCmptOptions);
  }

  makeIdAndName(result); // The array `result` MUST NOT contain elided items, otherwise the
  // forEach will ommit those items and result in incorrect result.

  return result;
}

function prepareResult(existings, existingIdIdxMap, mode) {
  var result = [];

  if (mode === 'replaceAll') {
    return result;
  } // Do not use native `map` to in case that the array `existings`
  // contains elided items, which will be ommited.


  for (var index = 0; index < existings.length; index++) {
    var existing = existings[index]; // Because of replaceMerge, `existing` may be null/undefined.

    if (existing && existing.id != null) {
      existingIdIdxMap.set(existing.id, index);
    } // For non-internal-componnets:
    //     Mode "normalMerge": all existings kept.
    //     Mode "replaceMerge": all existing removed unless mapped by id.
    // For internal-components:
    //     go with "replaceMerge" approach in both mode.


    result.push({
      existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing,
      newOption: null,
      keyInfo: null,
      brandNew: null
    });
  }

  return result;
}

function mappingById(result, existings, existingIdIdxMap, newCmptOptions) {
  // Mapping by id if specified.
  each(newCmptOptions, function (cmptOption, index) {
    if (!cmptOption || cmptOption.id == null) {
      return;
    }

    var optionId = makeComparableKey(cmptOption.id);
    var existingIdx = existingIdIdxMap.get(optionId);

    if (existingIdx != null) {
      var resultItem = result[existingIdx];
      assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".');
      resultItem.newOption = cmptOption; // In both mode, if id matched, new option will be merged to
      // the existings rather than creating new component model.

      resultItem.existing = existings[existingIdx];
      newCmptOptions[index] = null;
    }
  });
}

function mappingByName(result, newCmptOptions) {
  // Mapping by name if specified.
  each(newCmptOptions, function (cmptOption, index) {
    if (!cmptOption || cmptOption.name == null) {
      return;
    }

    for (var i = 0; i < result.length; i++) {
      var existing = result[i].existing;

      if (!result[i].newOption // Consider name: two map to one.
      // Can not match when both ids existing but different.
      && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) {
        result[i].newOption = cmptOption;
        newCmptOptions[index] = null;
        return;
      }
    }
  });
}

function mappingByIndex(result, newCmptOptions, brandNew) {
  each(newCmptOptions, function (cmptOption) {
    if (!cmptOption) {
      return;
    } // Find the first place that not mapped by id and not internal component (consider the "hole").


    var resultItem;
    var nextIdx = 0;

    while ( // Be `!resultItem` only when `nextIdx >= result.length`.
    (resultItem = result[nextIdx]) && ( // (1) Existing models that already have id should be able to mapped to. Because
    // after mapping performed, model will always be assigned with an id if user not given.
    // After that all models have id.
    // (2) If new option has id, it can only set to a hole or append to the last. It should
    // not be merged to the existings with different id. Because id should not be overwritten.
    // (3) Name can be overwritten, because axis use name as 'show label text'.
    resultItem.newOption || isComponentIdInternal(resultItem.existing) || // In mode "replaceMerge", here no not-mapped-non-internal-existing.
    resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) {
      nextIdx++;
    }

    if (resultItem) {
      resultItem.newOption = cmptOption;
      resultItem.brandNew = brandNew;
    } else {
      result.push({
        newOption: cmptOption,
        brandNew: brandNew,
        existing: null,
        keyInfo: null
      });
    }

    nextIdx++;
  });
}

function mappingInReplaceAllMode(result, newCmptOptions) {
  each(newCmptOptions, function (cmptOption) {
    // The feature "reproduce" requires "hole" will also reproduced
    // in case that compoennt index referring are broken.
    result.push({
      newOption: cmptOption,
      brandNew: true,
      existing: null,
      keyInfo: null
    });
  });
}
/**
 * Make id and name for mapping result (result of mappingToExists)
 * into `keyInfo` field.
 */


function makeIdAndName(mapResult) {
  // We use this id to hash component models and view instances
  // in echarts. id can be specified by user, or auto generated.
  // The id generation rule ensures new view instance are able
  // to mapped to old instance when setOption are called in
  // no-merge mode. So we generate model id by name and plus
  // type in view id.
  // name can be duplicated among components, which is convenient
  // to specify multi components (like series) by one name.
  // Ensure that each id is distinct.
  var idMap = createHashMap();
  each(mapResult, function (item) {
    var existing = item.existing;
    existing && idMap.set(existing.id, item);
  });
  each(mapResult, function (item) {
    var opt = item.newOption; // Force ensure id not duplicated.

    assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id));
    opt && opt.id != null && idMap.set(opt.id, item);
    !item.keyInfo && (item.keyInfo = {});
  }); // Make name and id.

  each(mapResult, function (item, index) {
    var existing = item.existing;
    var opt = item.newOption;
    var keyInfo = item.keyInfo;

    if (!isObject(opt)) {
      return;
    } // name can be overwitten. Consider case: axis.name = '20km'.
    // But id generated by name will not be changed, which affect
    // only in that case: setOption with 'not merge mode' and view
    // instance will be recreated, which can be accepted.


    keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name // Avoid diffferent series has the same name,
    // because name may be used like in color pallet.
    : DUMMY_COMPONENT_NAME_PREFIX + index;

    if (existing) {
      keyInfo.id = makeComparableKey(existing.id);
    } else if (opt.id != null) {
      keyInfo.id = makeComparableKey(opt.id);
    } else {
      // Consider this situatoin:
      //  optionA: [{name: 'a'}, {name: 'a'}, {..}]
      //  optionB [{..}, {name: 'a'}, {name: 'a'}]
      // Series with the same name between optionA and optionB
      // should be mapped.
      var idNum = 0;

      do {
        keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++;
      } while (idMap.get(keyInfo.id));
    }

    idMap.set(keyInfo.id, item);
  });
}

function keyExistAndEqual(attr, obj1, obj2) {
  var key1 = convertOptionIdName(obj1[attr], null);
  var key2 = convertOptionIdName(obj2[attr], null); // See `MappingExistingItem`. `id` and `name` trade string equals to number.

  return key1 != null && key2 != null && key1 === key2;
}
/**
 * @return return null if not exist.
 */


function makeComparableKey(val) {
  if (true) {
    if (val == null) {
      throw new Error();
    }
  }

  return convertOptionIdName(val, '');
}

function convertOptionIdName(idOrName, defaultValue) {
  if (idOrName == null) {
    return defaultValue;
  }

  var type = typeof idOrName;
  return type === 'string' ? idOrName : type === 'number' || isStringSafe(idOrName) ? idOrName + '' : defaultValue;
}

function warnInvalidateIdOrName(idOrName) {
  if (true) {
    warn('`' + idOrName + '` is invalid id or name. Must be a string or number.');
  }
}

function isValidIdOrName(idOrName) {
  return isStringSafe(idOrName) || isNumeric(idOrName);
}

function isNameSpecified(componentModel) {
  var name = componentModel.name; // Is specified when `indexOf` get -1 or > 0.

  return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));
}
/**
 * @public
 * @param {Object} cmptOption
 * @return {boolean}
 */

function isComponentIdInternal(cmptOption) {
  return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0;
}
function makeInternalComponentId(idSuffix) {
  return INTERNAL_COMPONENT_ID_PREFIX + idSuffix;
}
function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) {
  // Set mainType and complete subType.
  each(mappingResult, function (item) {
    var newOption = item.newOption;

    if (isObject(newOption)) {
      item.keyInfo.mainType = mainType;
      item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor);
    }
  });
}

function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) {
  var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent.
  : componentModelCtor.determineSubType(mainType, newCmptOption); // tooltip, markline, markpoint may always has no subType

  return subType;
}
/**
 * A helper for removing duplicate items between batchA and batchB,
 * and in themselves, and categorize by series.
 *
 * @param batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
 * @param batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
 * @return result: [resultBatchA, resultBatchB]
 */


function compressBatches(batchA, batchB) {
  var mapA = {};
  var mapB = {};
  makeMap(batchA || [], mapA);
  makeMap(batchB || [], mapB, mapA);
  return [mapToArray(mapA), mapToArray(mapB)];

  function makeMap(sourceBatch, map, otherMap) {
    for (var i = 0, len = sourceBatch.length; i < len; i++) {
      var seriesId = convertOptionIdName(sourceBatch[i].seriesId, null);

      if (seriesId == null) {
        return;
      }

      var dataIndices = normalizeToArray(sourceBatch[i].dataIndex);
      var otherDataIndices = otherMap && otherMap[seriesId];

      for (var j = 0, lenj = dataIndices.length; j < lenj; j++) {
        var dataIndex = dataIndices[j];

        if (otherDataIndices && otherDataIndices[dataIndex]) {
          otherDataIndices[dataIndex] = null;
        } else {
          (map[seriesId] || (map[seriesId] = {}))[dataIndex] = 1;
        }
      }
    }
  }

  function mapToArray(map, isData) {
    var result = [];

    for (var i in map) {
      if (map.hasOwnProperty(i) && map[i] != null) {
        if (isData) {
          result.push(+i);
        } else {
          var dataIndices = mapToArray(map[i], true);
          dataIndices.length && result.push({
            seriesId: i,
            dataIndex: dataIndices
          });
        }
      }
    }

    return result;
  }
}
/**
 * @param payload Contains dataIndex (means rawIndex) / dataIndexInside / name
 *                         each of which can be Array or primary type.
 * @return dataIndex If not found, return undefined/null.
 */

function queryDataIndex(data, payload) {
  if (payload.dataIndexInside != null) {
    return payload.dataIndexInside;
  } else if (payload.dataIndex != null) {
    return isArray(payload.dataIndex) ? map(payload.dataIndex, function (value) {
      return data.indexOfRawIndex(value);
    }) : data.indexOfRawIndex(payload.dataIndex);
  } else if (payload.name != null) {
    return isArray(payload.name) ? map(payload.name, function (value) {
      return data.indexOfName(value);
    }) : data.indexOfName(payload.name);
  }
}
/**
 * Enable property storage to any host object.
 * Notice: Serialization is not supported.
 *
 * For example:
 * let inner = zrUitl.makeInner();
 *
 * function some1(hostObj) {
 *      inner(hostObj).someProperty = 1212;
 *      ...
 * }
 * function some2() {
 *      let fields = inner(this);
 *      fields.someProperty1 = 1212;
 *      fields.someProperty2 = 'xx';
 *      ...
 * }
 *
 * @return {Function}
 */

function makeInner() {
  var key = '__ec_inner_' + innerUniqueIndex++;
  return function (hostObj) {
    return hostObj[key] || (hostObj[key] = {});
  };
}
var innerUniqueIndex = getRandomIdBase();
/**
 * The same behavior as `component.getReferringComponents`.
 */

function parseFinder(ecModel, finderInput, opt) {
  var _a = preParseFinder(finderInput, opt),
      mainTypeSpecified = _a.mainTypeSpecified,
      queryOptionMap = _a.queryOptionMap,
      others = _a.others;

  var result = others;
  var defaultMainType = opt ? opt.defaultMainType : null;

  if (!mainTypeSpecified && defaultMainType) {
    queryOptionMap.set(defaultMainType, {});
  }

  queryOptionMap.each(function (queryOption, mainType) {
    var queryResult = queryReferringComponents(ecModel, mainType, queryOption, {
      useDefault: defaultMainType === mainType,
      enableAll: opt && opt.enableAll != null ? opt.enableAll : true,
      enableNone: opt && opt.enableNone != null ? opt.enableNone : true
    });
    result[mainType + 'Models'] = queryResult.models;
    result[mainType + 'Model'] = queryResult.models[0];
  });
  return result;
}
function preParseFinder(finderInput, opt) {
  var finder;

  if (isString(finderInput)) {
    var obj = {};
    obj[finderInput + 'Index'] = 0;
    finder = obj;
  } else {
    finder = finderInput;
  }

  var queryOptionMap = createHashMap();
  var others = {};
  var mainTypeSpecified = false;
  each(finder, function (value, key) {
    // Exclude 'dataIndex' and other illgal keys.
    if (key === 'dataIndex' || key === 'dataIndexInside') {
      others[key] = value;
      return;
    }

    var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || [];
    var mainType = parsedKey[1];
    var queryType = (parsedKey[2] || '').toLowerCase();

    if (!mainType || !queryType || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) {
      return;
    }

    mainTypeSpecified = mainTypeSpecified || !!mainType;
    var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {});
    queryOption[queryType] = value;
  });
  return {
    mainTypeSpecified: mainTypeSpecified,
    queryOptionMap: queryOptionMap,
    others: others
  };
}
var SINGLE_REFERRING = {
  useDefault: true,
  enableAll: false,
  enableNone: false
};
var MULTIPLE_REFERRING = {
  useDefault: false,
  enableAll: true,
  enableNone: true
};
function queryReferringComponents(ecModel, mainType, userOption, opt) {
  opt = opt || SINGLE_REFERRING;
  var indexOption = userOption.index;
  var idOption = userOption.id;
  var nameOption = userOption.name;
  var result = {
    models: null,
    specified: indexOption != null || idOption != null || nameOption != null
  };

  if (!result.specified) {
    // Use the first as default if `useDefault`.
    var firstCmpt = void 0;
    result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : [];
    return result;
  }

  if (indexOption === 'none' || indexOption === false) {
    assert(opt.enableNone, '`"none"` or `false` is not a valid value on index option.');
    result.models = [];
    return result;
  } // `queryComponents` will return all components if
  // both all of index/id/name are null/undefined.


  if (indexOption === 'all') {
    assert(opt.enableAll, '`"all"` is not a valid value on index option.');
    indexOption = idOption = nameOption = null;
  }

  result.models = ecModel.queryComponents({
    mainType: mainType,
    index: indexOption,
    id: idOption,
    name: nameOption
  });
  return result;
}
function setAttribute(dom, key, value) {
  dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value;
}
function getAttribute(dom, key) {
  return dom.getAttribute ? dom.getAttribute(key) : dom[key];
}
function getTooltipRenderMode(renderModeOption) {
  if (renderModeOption === 'auto') {
    // Using html when `document` exists, use richText otherwise
    return core_env.domSupported ? 'html' : 'richText';
  } else {
    return renderModeOption || 'html';
  }
}
/**
 * Group a list by key.
 */

function groupData(array, getKey // return key
) {
  var buckets = createHashMap();
  var keys = [];
  each(array, function (item) {
    var key = getKey(item);
    (buckets.get(key) || (keys.push(key), buckets.set(key, []))).push(item);
  });
  return {
    keys: keys,
    buckets: buckets
  };
}
/**
 * Interpolate raw values of a series with percent
 *
 * @param data         data
 * @param labelModel   label model of the text element
 * @param sourceValue  start value. May be null/undefined when init.
 * @param targetValue  end value
 * @param percent      0~1 percentage; 0 uses start value while 1 uses end value
 * @return             interpolated values
 *                     If `sourceValue` and `targetValue` are `number`, return `number`.
 *                     If `sourceValue` and `targetValue` are `string`, return `string`.
 *                     If `sourceValue` and `targetValue` are `(string | number)[]`, return `(string | number)[]`.
 *                     Other cases do not supported.
 */

function interpolateRawValues(data, precision, sourceValue, targetValue, percent) {
  var isAutoPrecision = precision == null || precision === 'auto';

  if (targetValue == null) {
    return targetValue;
  }

  if (typeof targetValue === 'number') {
    var value = interpolateNumber(sourceValue || 0, targetValue, percent);
    return number_round(value, isAutoPrecision ? Math.max(getPrecision(sourceValue || 0), getPrecision(targetValue)) : precision);
  } else if (typeof targetValue === 'string') {
    return percent < 1 ? sourceValue : targetValue;
  } else {
    var interpolated = [];
    var leftArr = sourceValue;
    var rightArr = targetValue;
    var length_1 = Math.max(leftArr ? leftArr.length : 0, rightArr.length);

    for (var i = 0; i < length_1; ++i) {
      var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims

      if (info.type === 'ordinal') {
        // In init, there is no `sourceValue`, but should better not to get undefined result.
        interpolated[i] = (percent < 1 && leftArr ? leftArr : rightArr)[i];
      } else {
        var leftVal = leftArr && leftArr[i] ? leftArr[i] : 0;
        var rightVal = rightArr[i];
        var value = interpolateNumber(leftVal, rightVal, percent);
        interpolated[i] = number_round(value, isAutoPrecision ? Math.max(getPrecision(leftVal), getPrecision(rightVal)) : precision);
      }
    }

    return interpolated;
  }
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/innerStore.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var getECData = makeInner();
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/states.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/






 // Reserve 0 as default.

var _highlightNextDigit = 1;
var _highlightKeyMap = {};
var getSavedStates = makeInner();
var HOVER_STATE_NORMAL = 0;
var HOVER_STATE_BLUR = 1;
var HOVER_STATE_EMPHASIS = 2;
var SPECIAL_STATES = ['emphasis', 'blur', 'select'];
var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select'];
var Z2_EMPHASIS_LIFT = 10;
var Z2_SELECT_LIFT = 9;
var HIGHLIGHT_ACTION_TYPE = 'highlight';
var DOWNPLAY_ACTION_TYPE = 'downplay';
var SELECT_ACTION_TYPE = 'select';
var UNSELECT_ACTION_TYPE = 'unselect';
var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect';

function hasFillOrStroke(fillOrStroke) {
  return fillOrStroke != null && fillOrStroke !== 'none';
} // Most lifted color are duplicated.


var liftedColorCache = new lib_core_LRU(100);

function liftColor(color) {
  if (typeof color !== 'string') {
    return color;
  }

  var liftedColor = liftedColorCache.get(color);

  if (!liftedColor) {
    liftedColor = lift(color, -0.1);
    liftedColorCache.put(color, liftedColor);
  }

  return liftedColor;
}

function doChangeHoverState(el, stateName, hoverStateEnum) {
  if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) {
    el.onHoverStateChange(stateName);
  }

  el.hoverState = hoverStateEnum;
}

function singleEnterEmphasis(el) {
  // Only mark the flag.
  // States will be applied in the echarts.ts in next frame.
  doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS);
}

function singleLeaveEmphasis(el) {
  // Only mark the flag.
  // States will be applied in the echarts.ts in next frame.
  if (el.hoverState === HOVER_STATE_EMPHASIS) {
    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  }
}

function singleEnterBlur(el) {
  doChangeHoverState(el, 'blur', HOVER_STATE_BLUR);
}

function singleLeaveBlur(el) {
  if (el.hoverState === HOVER_STATE_BLUR) {
    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
  }
}

function singleEnterSelect(el) {
  el.selected = true;
}

function singleLeaveSelect(el) {
  el.selected = false;
}

function updateElementState(el, updater, commonParam) {
  updater(el, commonParam);
}

function traverseUpdateState(el, updater, commonParam) {
  updateElementState(el, updater, commonParam);
  el.isGroup && el.traverse(function (child) {
    updateElementState(child, updater, commonParam);
  });
}

function setStatesFlag(el, stateName) {
  switch (stateName) {
    case 'emphasis':
      el.hoverState = HOVER_STATE_EMPHASIS;
      break;

    case 'normal':
      el.hoverState = HOVER_STATE_NORMAL;
      break;

    case 'blur':
      el.hoverState = HOVER_STATE_BLUR;
      break;

    case 'select':
      el.selected = true;
  }
}
/**
 * If we reuse elements when rerender.
 * DONT forget to clearStates before we update the style and shape.
 * Or we may update on the wrong state instead of normal state.
 */

function clearStates(el) {
  if (el.isGroup) {
    el.traverse(function (child) {
      child.clearStates();
    });
  } else {
    el.clearStates();
  }
}

function getFromStateStyle(el, props, toStateName, defaultValue) {
  var style = el.style;
  var fromState = {};

  for (var i = 0; i < props.length; i++) {
    var propName = props[i];
    var val = style[propName];
    fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val;
  }

  for (var i = 0; i < el.animators.length; i++) {
    var animator = el.animators[i];

    if (animator.__fromStateTransition // Dont consider the animation to emphasis state.
    && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') {
      animator.saveFinalToTarget(fromState, props);
    }
  }

  return fromState;
}

function createEmphasisDefaultState(el, stateName, targetStates, state) {
  var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0;
  var cloned = false;

  if (el instanceof graphic_Path) {
    var store = getSavedStates(el);
    var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill;
    var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke;

    if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) {
      state = state || {}; // Apply default color lift

      var emphasisStyle = state.style || {};

      if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) {
        cloned = true; // Not modify the original value.

        state = util_extend({}, state);
        emphasisStyle = util_extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times.

        emphasisStyle.fill = liftColor(fromFill);
      } // Not highlight stroke if fill has been highlighted.
      else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) {
          if (!cloned) {
            state = util_extend({}, state);
            emphasisStyle = util_extend({}, emphasisStyle);
          }

          emphasisStyle.stroke = liftColor(fromStroke);
        }

      state.style = emphasisStyle;
    }
  }

  if (state) {
    // TODO Share with textContent?
    if (state.z2 == null) {
      if (!cloned) {
        state = util_extend({}, state);
      }

      var z2EmphasisLift = el.z2EmphasisLift;
      state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
    }
  }

  return state;
}

function createSelectDefaultState(el, stateName, state) {
  // const hasSelect = indexOf(el.currentStates, stateName) >= 0;
  if (state) {
    // TODO Share with textContent?
    if (state.z2 == null) {
      state = util_extend({}, state);
      var z2SelectLift = el.z2SelectLift;
      state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT);
    }
  }

  return state;
}

function createBlurDefaultState(el, stateName, state) {
  var hasBlur = indexOf(el.currentStates, stateName) >= 0;
  var currentOpacity = el.style.opacity;
  var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, {
    opacity: 1
  }) : null;
  state = state || {};
  var blurStyle = state.style || {};

  if (blurStyle.opacity == null) {
    // clone state
    state = util_extend({}, state);
    blurStyle = util_extend({
      // Already being applied 'emphasis'. DON'T mul opacity multiple times.
      opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1
    }, blurStyle);
    state.style = blurStyle;
  }

  return state;
}

function elementStateProxy(stateName, targetStates) {
  var state = this.states[stateName];

  if (this.style) {
    if (stateName === 'emphasis') {
      return createEmphasisDefaultState(this, stateName, targetStates, state);
    } else if (stateName === 'blur') {
      return createBlurDefaultState(this, stateName, state);
    } else if (stateName === 'select') {
      return createSelectDefaultState(this, stateName, state);
    }
  }

  return state;
}
/**FI
 * Set hover style (namely "emphasis style") of element.
 * @param el Should not be `zrender/graphic/Group`.
 * @param focus 'self' | 'selfInSeries' | 'series'
 */


function setDefaultStateProxy(el) {
  el.stateProxy = elementStateProxy;
  var textContent = el.getTextContent();
  var textGuide = el.getTextGuideLine();

  if (textContent) {
    textContent.stateProxy = elementStateProxy;
  }

  if (textGuide) {
    textGuide.stateProxy = elementStateProxy;
  }
}
function enterEmphasisWhenMouseOver(el, e) {
  !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
  && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis);
}
function leaveEmphasisWhenMouseOut(el, e) {
  !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
  && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis);
}
function enterEmphasis(el, highlightDigit) {
  el.__highByOuter |= 1 << (highlightDigit || 0);
  traverseUpdateState(el, singleEnterEmphasis);
}
function leaveEmphasis(el, highlightDigit) {
  !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis);
}
function enterBlur(el) {
  traverseUpdateState(el, singleEnterBlur);
}
function leaveBlur(el) {
  traverseUpdateState(el, singleLeaveBlur);
}
function enterSelect(el) {
  traverseUpdateState(el, singleEnterSelect);
}
function leaveSelect(el) {
  traverseUpdateState(el, singleLeaveSelect);
}

function shouldSilent(el, e) {
  return el.__highDownSilentOnTouch && e.zrByTouch;
}

function allLeaveBlur(api) {
  var model = api.getModel();
  model.eachComponent(function (componentType, componentModel) {
    var view = componentType === 'series' ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel); // Leave blur anyway

    view.group.traverse(function (child) {
      singleLeaveBlur(child);
    });
  });
}
function blurSeries(targetSeriesIndex, focus, blurScope, api) {
  var ecModel = api.getModel();
  blurScope = blurScope || 'coordinateSystem';

  function leaveBlurOfIndices(data, dataIndices) {
    for (var i = 0; i < dataIndices.length; i++) {
      var itemEl = data.getItemGraphicEl(dataIndices[i]);
      itemEl && leaveBlur(itemEl);
    }
  }

  if (targetSeriesIndex == null) {
    return;
  }

  if (!focus || focus === 'none') {
    return;
  }

  var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex);
  var targetCoordSys = targetSeriesModel.coordinateSystem;

  if (targetCoordSys && targetCoordSys.master) {
    targetCoordSys = targetCoordSys.master;
  }

  var blurredSeries = [];
  ecModel.eachSeries(function (seriesModel) {
    var sameSeries = targetSeriesModel === seriesModel;
    var coordSys = seriesModel.coordinateSystem;

    if (coordSys && coordSys.master) {
      coordSys = coordSys.master;
    }

    var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead.

    if (!( // Not blur other series if blurScope series
    blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem
    || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series.
    || focus === 'series' && sameSeries // TODO blurScope: coordinate system
    )) {
      var view = api.getViewOfSeriesModel(seriesModel);
      view.group.traverse(function (child) {
        singleEnterBlur(child);
      });

      if (isArrayLike(focus)) {
        leaveBlurOfIndices(seriesModel.getData(), focus);
      } else if (isObject(focus)) {
        var dataTypes = keys(focus);

        for (var d = 0; d < dataTypes.length; d++) {
          leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]);
        }
      }

      blurredSeries.push(seriesModel);
    }
  });
  ecModel.eachComponent(function (componentType, componentModel) {
    if (componentType === 'series') {
      return;
    }

    var view = api.getViewOfComponentModel(componentModel);

    if (view && view.blurSeries) {
      view.blurSeries(blurredSeries, ecModel);
    }
  });
}
function blurComponent(componentMainType, componentIndex, api) {
  if (componentMainType == null || componentIndex == null) {
    return;
  }

  var componentModel = api.getModel().getComponent(componentMainType, componentIndex);

  if (!componentModel) {
    return;
  }

  var view = api.getViewOfComponentModel(componentModel);

  if (!view || !view.focusBlurEnabled) {
    return;
  }

  view.group.traverse(function (child) {
    singleEnterBlur(child);
  });
}
function blurSeriesFromHighlightPayload(seriesModel, payload, api) {
  var seriesIndex = seriesModel.seriesIndex;
  var data = seriesModel.getData(payload.dataType);
  var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists.

  dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0;
  var el = data.getItemGraphicEl(dataIndex);

  if (!el) {
    var count = data.count();
    var current = 0; // If data on dataIndex is NaN.

    while (!el && current < count) {
      el = data.getItemGraphicEl(current++);
    }
  }

  if (el) {
    var ecData = getECData(el);
    blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api);
  } else {
    // If there is no element put on the data. Try getting it from raw option
    // TODO Should put it on seriesModel?
    var focus_1 = seriesModel.get(['emphasis', 'focus']);
    var blurScope = seriesModel.get(['emphasis', 'blurScope']);

    if (focus_1 != null) {
      blurSeries(seriesIndex, focus_1, blurScope, api);
    }
  }
}
function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) {
  var ret = {
    focusSelf: false,
    dispatchers: null
  };

  if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) {
    return ret;
  }

  var componentModel = api.getModel().getComponent(componentMainType, componentIndex);

  if (!componentModel) {
    return ret;
  }

  var view = api.getViewOfComponentModel(componentModel);

  if (!view || !view.findHighDownDispatchers) {
    return ret;
  }

  var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself.
  // So we do not use `blurScope` in component.

  var focusSelf;

  for (var i = 0; i < dispatchers.length; i++) {
    if ( true && !isHighDownDispatcher(dispatchers[i])) {
      error('param should be highDownDispatcher');
    }

    if (getECData(dispatchers[i]).focus === 'self') {
      focusSelf = true;
      break;
    }
  }

  return {
    focusSelf: focusSelf,
    dispatchers: dispatchers
  };
}
function handleGlobalMouseOverForHighDown(dispatcher, e, api) {
  if ( true && !isHighDownDispatcher(dispatcher)) {
    error('param should be highDownDispatcher');
  }

  var ecData = getECData(dispatcher);

  var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api),
      dispatchers = _a.dispatchers,
      focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component,
  // highlight/downplay elements with the same name.


  if (dispatchers) {
    if (focusSelf) {
      blurComponent(ecData.componentMainType, ecData.componentIndex, api);
    }

    each(dispatchers, function (dispatcher) {
      return enterEmphasisWhenMouseOver(dispatcher, e);
    });
  } else {
    // Try blur all in the related series. Then emphasis the hoverred.
    // TODO. progressive mode.
    blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api);

    if (ecData.focus === 'self') {
      blurComponent(ecData.componentMainType, ecData.componentIndex, api);
    } // Other than series, component that not support `findHighDownDispatcher` will
    // also use it. But in this case, highlight/downplay are only supported in
    // mouse hover but not in dispatchAction.


    enterEmphasisWhenMouseOver(dispatcher, e);
  }
}
function handleGlboalMouseOutForHighDown(dispatcher, e, api) {
  if ( true && !isHighDownDispatcher(dispatcher)) {
    error('param should be highDownDispatcher');
  }

  allLeaveBlur(api);
  var ecData = getECData(dispatcher);
  var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers;

  if (dispatchers) {
    each(dispatchers, function (dispatcher) {
      return leaveEmphasisWhenMouseOut(dispatcher, e);
    });
  } else {
    leaveEmphasisWhenMouseOut(dispatcher, e);
  }
}
function toggleSelectionFromPayload(seriesModel, payload, api) {
  if (!isSelectChangePayload(payload)) {
    return;
  }

  var dataType = payload.dataType;
  var data = seriesModel.getData(dataType);
  var dataIndex = queryDataIndex(data, payload);

  if (!isArray(dataIndex)) {
    dataIndex = [dataIndex];
  }

  seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType);
}
function updateSeriesElementSelection(seriesModel) {
  var allData = seriesModel.getAllData();
  each(allData, function (_a) {
    var data = _a.data,
        type = _a.type;
    data.eachItemGraphicEl(function (el, idx) {
      seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el);
    });
  });
}
function getAllSelectedIndices(ecModel) {
  var ret = [];
  ecModel.eachSeries(function (seriesModel) {
    var allData = seriesModel.getAllData();
    each(allData, function (_a) {
      var data = _a.data,
          type = _a.type;
      var dataIndices = seriesModel.getSelectedDataIndices();

      if (dataIndices.length > 0) {
        var item = {
          dataIndex: dataIndices,
          seriesIndex: seriesModel.seriesIndex
        };

        if (type != null) {
          item.dataType = type;
        }

        ret.push(item);
      }
    });
  });
  return ret;
}
/**
 * Enable the function that mouseover will trigger the emphasis state.
 *
 * NOTE:
 * This function should be used on the element with dataIndex, seriesIndex.
 *
 */

function enableHoverEmphasis(el, focus, blurScope) {
  setAsHighDownDispatcher(el, true);
  traverseUpdateState(el, setDefaultStateProxy);
  enableHoverFocus(el, focus, blurScope);
}
function enableHoverFocus(el, focus, blurScope) {
  var ecData = getECData(el);

  if (focus != null) {
    // TODO dataIndex may be set after this function. This check is not useful.
    // if (ecData.dataIndex == null) {
    //     if (__DEV__) {
    //         console.warn('focus can only been set on element with dataIndex');
    //     }
    // }
    // else {
    ecData.focus = focus;
    ecData.blurScope = blurScope; // }
  } else if (ecData.focus) {
    ecData.focus = null;
  }
}
var OTHER_STATES = ['emphasis', 'blur', 'select'];
var defaultStyleGetterMap = {
  itemStyle: 'getItemStyle',
  lineStyle: 'getLineStyle',
  areaStyle: 'getAreaStyle'
};
/**
 * Set emphasis/blur/selected states of element.
 */

function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle
getter) {
  styleType = styleType || 'itemStyle';

  for (var i = 0; i < OTHER_STATES.length; i++) {
    var stateName = OTHER_STATES[i];
    var model = itemModel.getModel([stateName, styleType]);
    var state = el.ensureState(stateName); // Let it throw error if getterType is not found.

    state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]]();
  }
}
/**
 * @parame el
 * @param el.highDownSilentOnTouch
 *        In touch device, mouseover event will be trigger on touchstart event
 *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can
 *        conveniently use hoverStyle when tap on touch screen without additional
 *        code for compatibility.
 *        But if the chart/component has select feature, which usually also use
 *        hoverStyle, there might be conflict between 'select-highlight' and
 *        'hover-highlight' especially when roam is enabled (see geo for example).
 *        In this case, `highDownSilentOnTouch` should be used to disable
 *        hover-highlight on touch device.
 * @param asDispatcher If `false`, do not set as "highDownDispatcher".
 */

function setAsHighDownDispatcher(el, asDispatcher) {
  var disable = asDispatcher === false;
  var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after
  // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly.

  if (el.highDownSilentOnTouch) {
    extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch;
  } // Simple optimize, since this method might be
  // called for each elements of a group in some cases.


  if (!disable || extendedEl.__highDownDispatcher) {
    // Emphasis, normal can be triggered manually by API or other components like hover link.
    // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent);
    // Also keep previous record.
    extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
    extendedEl.__highDownDispatcher = !disable;
  }
}
function isHighDownDispatcher(el) {
  return !!(el && el.__highDownDispatcher);
}
/**
 * Enable component highlight/downplay features:
 * + hover link (within the same name)
 * + focus blur in component
 */

function enableComponentHighDownFeatures(el, componentModel, componentHighDownName) {
  var ecData = getECData(el);
  ecData.componentMainType = componentModel.mainType;
  ecData.componentIndex = componentModel.componentIndex;
  ecData.componentHighDownName = componentHighDownName;
}
/**
 * Support hightlight/downplay record on each elements.
 * For the case: hover highlight/downplay (legend, visualMap, ...) and
 * user triggerred hightlight/downplay should not conflict.
 * Only all of the highlightDigit cleared, return to normal.
 * @param {string} highlightKey
 * @return {number} highlightDigit
 */

function getHighlightDigit(highlightKey) {
  var highlightDigit = _highlightKeyMap[highlightKey];

  if (highlightDigit == null && _highlightNextDigit <= 32) {
    highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
  }

  return highlightDigit;
}
function isSelectChangePayload(payload) {
  var payloadType = payload.type;
  return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE;
}
function isHighDownPayload(payload) {
  var payloadType = payload.type;
  return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE;
}
function savePathStates(el) {
  var store = getSavedStates(el);
  store.normalFill = el.style.fill;
  store.normalStroke = el.style.stroke;
  var selectState = el.states.select || {};
  store.selectFill = selectState.style && selectState.style.fill || null;
  store.selectStroke = selectState.style && selectState.style.stroke || null;
}
;// CONCATENATED MODULE: ./node_modules/zrender/lib/tool/transformPath.js


var transformPath_CMD = core_PathProxy.CMD;
var points = [[], [], []];
var transformPath_mathSqrt = Math.sqrt;
var mathAtan2 = Math.atan2;
function transformPath(path, m) {
    var data = path.data;
    var len = path.len();
    var cmd;
    var nPoint;
    var i;
    var j;
    var k;
    var p;
    var M = transformPath_CMD.M;
    var C = transformPath_CMD.C;
    var L = transformPath_CMD.L;
    var R = transformPath_CMD.R;
    var A = transformPath_CMD.A;
    var Q = transformPath_CMD.Q;
    for (i = 0, j = 0; i < len;) {
        cmd = data[i++];
        j = i;
        nPoint = 0;
        switch (cmd) {
            case M:
                nPoint = 1;
                break;
            case L:
                nPoint = 1;
                break;
            case C:
                nPoint = 3;
                break;
            case Q:
                nPoint = 2;
                break;
            case A:
                var x = m[4];
                var y = m[5];
                var sx = transformPath_mathSqrt(m[0] * m[0] + m[1] * m[1]);
                var sy = transformPath_mathSqrt(m[2] * m[2] + m[3] * m[3]);
                var angle = mathAtan2(-m[1] / sy, m[0] / sx);
                data[i] *= sx;
                data[i++] += x;
                data[i] *= sy;
                data[i++] += y;
                data[i++] *= sx;
                data[i++] *= sy;
                data[i++] += angle;
                data[i++] += angle;
                i += 2;
                j = i;
                break;
            case R:
                p[0] = data[i++];
                p[1] = data[i++];
                applyTransform(p, p, m);
                data[j++] = p[0];
                data[j++] = p[1];
                p[0] += data[i++];
                p[1] += data[i++];
                applyTransform(p, p, m);
                data[j++] = p[0];
                data[j++] = p[1];
        }
        for (k = 0; k < nPoint; k++) {
            var p_1 = points[k];
            p_1[0] = data[i++];
            p_1[1] = data[i++];
            applyTransform(p_1, p_1, m);
            data[j++] = p_1[0];
            data[j++] = p_1[1];
        }
    }
    path.increaseVersion();
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/tool/path.js





var path_mathSqrt = Math.sqrt;
var path_mathSin = Math.sin;
var path_mathCos = Math.cos;
var path_PI = Math.PI;
function vMag(v) {
    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
}
;
function vRatio(u, v) {
    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
}
;
function vAngle(u, v) {
    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1)
        * Math.acos(vRatio(u, v));
}
;
function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
    var psi = psiDeg * (path_PI / 180.0);
    var xp = path_mathCos(psi) * (x1 - x2) / 2.0
        + path_mathSin(psi) * (y1 - y2) / 2.0;
    var yp = -1 * path_mathSin(psi) * (x1 - x2) / 2.0
        + path_mathCos(psi) * (y1 - y2) / 2.0;
    var lambda = (xp * xp) / (rx * rx) + (yp * yp) / (ry * ry);
    if (lambda > 1) {
        rx *= path_mathSqrt(lambda);
        ry *= path_mathSqrt(lambda);
    }
    var f = (fa === fs ? -1 : 1)
        * path_mathSqrt((((rx * rx) * (ry * ry))
            - ((rx * rx) * (yp * yp))
            - ((ry * ry) * (xp * xp))) / ((rx * rx) * (yp * yp)
            + (ry * ry) * (xp * xp))) || 0;
    var cxp = f * rx * yp / ry;
    var cyp = f * -ry * xp / rx;
    var cx = (x1 + x2) / 2.0
        + path_mathCos(psi) * cxp
        - path_mathSin(psi) * cyp;
    var cy = (y1 + y2) / 2.0
        + path_mathSin(psi) * cxp
        + path_mathCos(psi) * cyp;
    var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
    var u = [(xp - cxp) / rx, (yp - cyp) / ry];
    var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
    var dTheta = vAngle(u, v);
    if (vRatio(u, v) <= -1) {
        dTheta = path_PI;
    }
    if (vRatio(u, v) >= 1) {
        dTheta = 0;
    }
    if (dTheta < 0) {
        var n = Math.round(dTheta / path_PI * 1e6) / 1e6;
        dTheta = path_PI * 2 + (n % 2) * path_PI;
    }
    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
}
var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;
var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;
function createPathProxyFromString(data) {
    var path = new core_PathProxy();
    if (!data) {
        return path;
    }
    var cpx = 0;
    var cpy = 0;
    var subpathX = cpx;
    var subpathY = cpy;
    var prevCmd;
    var CMD = core_PathProxy.CMD;
    var cmdList = data.match(commandReg);
    if (!cmdList) {
        return path;
    }
    for (var l = 0; l < cmdList.length; l++) {
        var cmdText = cmdList[l];
        var cmdStr = cmdText.charAt(0);
        var cmd = void 0;
        var p = cmdText.match(numberReg) || [];
        var pLen = p.length;
        for (var i = 0; i < pLen; i++) {
            p[i] = parseFloat(p[i]);
        }
        var off = 0;
        while (off < pLen) {
            var ctlPtx = void 0;
            var ctlPty = void 0;
            var rx = void 0;
            var ry = void 0;
            var psi = void 0;
            var fa = void 0;
            var fs = void 0;
            var x1 = cpx;
            var y1 = cpy;
            var len = void 0;
            var pathData = void 0;
            switch (cmdStr) {
                case 'l':
                    cpx += p[off++];
                    cpy += p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'L':
                    cpx = p[off++];
                    cpy = p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'm':
                    cpx += p[off++];
                    cpy += p[off++];
                    cmd = CMD.M;
                    path.addData(cmd, cpx, cpy);
                    subpathX = cpx;
                    subpathY = cpy;
                    cmdStr = 'l';
                    break;
                case 'M':
                    cpx = p[off++];
                    cpy = p[off++];
                    cmd = CMD.M;
                    path.addData(cmd, cpx, cpy);
                    subpathX = cpx;
                    subpathY = cpy;
                    cmdStr = 'L';
                    break;
                case 'h':
                    cpx += p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'H':
                    cpx = p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'v':
                    cpy += p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'V':
                    cpy = p[off++];
                    cmd = CMD.L;
                    path.addData(cmd, cpx, cpy);
                    break;
                case 'C':
                    cmd = CMD.C;
                    path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]);
                    cpx = p[off - 2];
                    cpy = p[off - 1];
                    break;
                case 'c':
                    cmd = CMD.C;
                    path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy);
                    cpx += p[off - 2];
                    cpy += p[off - 1];
                    break;
                case 'S':
                    ctlPtx = cpx;
                    ctlPty = cpy;
                    len = path.len();
                    pathData = path.data;
                    if (prevCmd === CMD.C) {
                        ctlPtx += cpx - pathData[len - 4];
                        ctlPty += cpy - pathData[len - 3];
                    }
                    cmd = CMD.C;
                    x1 = p[off++];
                    y1 = p[off++];
                    cpx = p[off++];
                    cpy = p[off++];
                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
                    break;
                case 's':
                    ctlPtx = cpx;
                    ctlPty = cpy;
                    len = path.len();
                    pathData = path.data;
                    if (prevCmd === CMD.C) {
                        ctlPtx += cpx - pathData[len - 4];
                        ctlPty += cpy - pathData[len - 3];
                    }
                    cmd = CMD.C;
                    x1 = cpx + p[off++];
                    y1 = cpy + p[off++];
                    cpx += p[off++];
                    cpy += p[off++];
                    path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
                    break;
                case 'Q':
                    x1 = p[off++];
                    y1 = p[off++];
                    cpx = p[off++];
                    cpy = p[off++];
                    cmd = CMD.Q;
                    path.addData(cmd, x1, y1, cpx, cpy);
                    break;
                case 'q':
                    x1 = p[off++] + cpx;
                    y1 = p[off++] + cpy;
                    cpx += p[off++];
                    cpy += p[off++];
                    cmd = CMD.Q;
                    path.addData(cmd, x1, y1, cpx, cpy);
                    break;
                case 'T':
                    ctlPtx = cpx;
                    ctlPty = cpy;
                    len = path.len();
                    pathData = path.data;
                    if (prevCmd === CMD.Q) {
                        ctlPtx += cpx - pathData[len - 4];
                        ctlPty += cpy - pathData[len - 3];
                    }
                    cpx = p[off++];
                    cpy = p[off++];
                    cmd = CMD.Q;
                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
                    break;
                case 't':
                    ctlPtx = cpx;
                    ctlPty = cpy;
                    len = path.len();
                    pathData = path.data;
                    if (prevCmd === CMD.Q) {
                        ctlPtx += cpx - pathData[len - 4];
                        ctlPty += cpy - pathData[len - 3];
                    }
                    cpx += p[off++];
                    cpy += p[off++];
                    cmd = CMD.Q;
                    path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
                    break;
                case 'A':
                    rx = p[off++];
                    ry = p[off++];
                    psi = p[off++];
                    fa = p[off++];
                    fs = p[off++];
                    x1 = cpx, y1 = cpy;
                    cpx = p[off++];
                    cpy = p[off++];
                    cmd = CMD.A;
                    processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
                    break;
                case 'a':
                    rx = p[off++];
                    ry = p[off++];
                    psi = p[off++];
                    fa = p[off++];
                    fs = p[off++];
                    x1 = cpx, y1 = cpy;
                    cpx += p[off++];
                    cpy += p[off++];
                    cmd = CMD.A;
                    processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
                    break;
            }
        }
        if (cmdStr === 'z' || cmdStr === 'Z') {
            cmd = CMD.Z;
            path.addData(cmd);
            cpx = subpathX;
            cpy = subpathY;
        }
        prevCmd = cmd;
    }
    path.toStatic();
    return path;
}
var SVGPath = (function (_super) {
    __extends(SVGPath, _super);
    function SVGPath() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    SVGPath.prototype.applyTransform = function (m) { };
    return SVGPath;
}(graphic_Path));
function isPathProxy(path) {
    return path.setData != null;
}
function createPathOptions(str, opts) {
    var pathProxy = createPathProxyFromString(str);
    var innerOpts = util_extend({}, opts);
    innerOpts.buildPath = function (path) {
        if (isPathProxy(path)) {
            path.setData(pathProxy.data);
            var ctx = path.getContext();
            if (ctx) {
                path.rebuildPath(ctx, 1);
            }
        }
        else {
            var ctx = path;
            pathProxy.rebuildPath(ctx, 1);
        }
    };
    innerOpts.applyTransform = function (m) {
        transformPath(pathProxy, m);
        this.dirtyShape();
    };
    return innerOpts;
}
function createFromString(str, opts) {
    return new SVGPath(createPathOptions(str, opts));
}
function extendFromString(str, defaultOpts) {
    var innerOpts = createPathOptions(str, defaultOpts);
    var Sub = (function (_super) {
        __extends(Sub, _super);
        function Sub(opts) {
            var _this = _super.call(this, opts) || this;
            _this.applyTransform = innerOpts.applyTransform;
            _this.buildPath = innerOpts.buildPath;
            return _this;
        }
        return Sub;
    }(SVGPath));
    return Sub;
}
function mergePath(pathEls, opts) {
    var pathList = [];
    var len = pathEls.length;
    for (var i = 0; i < len; i++) {
        var pathEl = pathEls[i];
        if (!pathEl.path) {
            pathEl.createPathProxy();
        }
        if (pathEl.shapeChanged()) {
            pathEl.buildPath(pathEl.path, pathEl.shape, true);
        }
        pathList.push(pathEl.path);
    }
    var pathBundle = new graphic_Path(opts);
    pathBundle.createPathProxy();
    pathBundle.buildPath = function (path) {
        if (isPathProxy(path)) {
            path.appendPath(pathList);
            var ctx = path.getContext();
            if (ctx) {
                path.rebuildPath(ctx, 1);
            }
        }
    };
    return pathBundle;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Group.js




var Group = (function (_super) {
    __extends(Group, _super);
    function Group(opts) {
        var _this = _super.call(this) || this;
        _this.isGroup = true;
        _this._children = [];
        _this.attr(opts);
        return _this;
    }
    Group.prototype.childrenRef = function () {
        return this._children;
    };
    Group.prototype.children = function () {
        return this._children.slice();
    };
    Group.prototype.childAt = function (idx) {
        return this._children[idx];
    };
    Group.prototype.childOfName = function (name) {
        var children = this._children;
        for (var i = 0; i < children.length; i++) {
            if (children[i].name === name) {
                return children[i];
            }
        }
    };
    Group.prototype.childCount = function () {
        return this._children.length;
    };
    Group.prototype.add = function (child) {
        if (child) {
            if (child !== this && child.parent !== this) {
                this._children.push(child);
                this._doAdd(child);
            }
            if (child.__hostTarget) {
                throw 'This elemenet has been used as an attachment';
            }
        }
        return this;
    };
    Group.prototype.addBefore = function (child, nextSibling) {
        if (child && child !== this && child.parent !== this
            && nextSibling && nextSibling.parent === this) {
            var children = this._children;
            var idx = children.indexOf(nextSibling);
            if (idx >= 0) {
                children.splice(idx, 0, child);
                this._doAdd(child);
            }
        }
        return this;
    };
    Group.prototype.replaceAt = function (child, index) {
        var children = this._children;
        var old = children[index];
        if (child && child !== this && child.parent !== this && child !== old) {
            children[index] = child;
            old.parent = null;
            var zr = this.__zr;
            if (zr) {
                old.removeSelfFromZr(zr);
            }
            this._doAdd(child);
        }
        return this;
    };
    Group.prototype._doAdd = function (child) {
        if (child.parent) {
            child.parent.remove(child);
        }
        child.parent = this;
        var zr = this.__zr;
        if (zr && zr !== child.__zr) {
            child.addSelfToZr(zr);
        }
        zr && zr.refresh();
    };
    Group.prototype.remove = function (child) {
        var zr = this.__zr;
        var children = this._children;
        var idx = indexOf(children, child);
        if (idx < 0) {
            return this;
        }
        children.splice(idx, 1);
        child.parent = null;
        if (zr) {
            child.removeSelfFromZr(zr);
        }
        zr && zr.refresh();
        return this;
    };
    Group.prototype.removeAll = function () {
        var children = this._children;
        var zr = this.__zr;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (zr) {
                child.removeSelfFromZr(zr);
            }
            child.parent = null;
        }
        children.length = 0;
        return this;
    };
    Group.prototype.eachChild = function (cb, context) {
        var children = this._children;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            cb.call(context, child, i);
        }
        return this;
    };
    Group.prototype.traverse = function (cb, context) {
        for (var i = 0; i < this._children.length; i++) {
            var child = this._children[i];
            var stopped = cb.call(context, child);
            if (child.isGroup && !stopped) {
                child.traverse(cb, context);
            }
        }
        return this;
    };
    Group.prototype.addSelfToZr = function (zr) {
        _super.prototype.addSelfToZr.call(this, zr);
        for (var i = 0; i < this._children.length; i++) {
            var child = this._children[i];
            child.addSelfToZr(zr);
        }
    };
    Group.prototype.removeSelfFromZr = function (zr) {
        _super.prototype.removeSelfFromZr.call(this, zr);
        for (var i = 0; i < this._children.length; i++) {
            var child = this._children[i];
            child.removeSelfFromZr(zr);
        }
    };
    Group.prototype.getBoundingRect = function (includeChildren) {
        var tmpRect = new core_BoundingRect(0, 0, 0, 0);
        var children = includeChildren || this._children;
        var tmpMat = [];
        var rect = null;
        for (var i = 0; i < children.length; i++) {
            var child = children[i];
            if (child.ignore || child.invisible) {
                continue;
            }
            var childRect = child.getBoundingRect();
            var transform = child.getLocalTransform(tmpMat);
            if (transform) {
                core_BoundingRect.applyTransform(tmpRect, childRect, transform);
                rect = rect || tmpRect.clone();
                rect.union(tmpRect);
            }
            else {
                rect = rect || childRect.clone();
                rect.union(childRect);
            }
        }
        return rect || tmpRect;
    };
    return Group;
}(lib_Element));
Group.prototype.type = 'group';
/* harmony default export */ const graphic_Group = (Group);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Circle.js


var CircleShape = (function () {
    function CircleShape() {
        this.cx = 0;
        this.cy = 0;
        this.r = 0;
    }
    return CircleShape;
}());

var Circle = (function (_super) {
    __extends(Circle, _super);
    function Circle(opts) {
        return _super.call(this, opts) || this;
    }
    Circle.prototype.getDefaultShape = function () {
        return new CircleShape();
    };
    Circle.prototype.buildPath = function (ctx, shape, inBundle) {
        if (inBundle) {
            ctx.moveTo(shape.cx + shape.r, shape.cy);
        }
        ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2);
    };
    return Circle;
}(graphic_Path));
;
Circle.prototype.type = 'circle';
/* harmony default export */ const shape_Circle = (Circle);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Ellipse.js


var EllipseShape = (function () {
    function EllipseShape() {
        this.cx = 0;
        this.cy = 0;
        this.rx = 0;
        this.ry = 0;
    }
    return EllipseShape;
}());

var Ellipse = (function (_super) {
    __extends(Ellipse, _super);
    function Ellipse(opts) {
        return _super.call(this, opts) || this;
    }
    Ellipse.prototype.getDefaultShape = function () {
        return new EllipseShape();
    };
    Ellipse.prototype.buildPath = function (ctx, shape) {
        var k = 0.5522848;
        var x = shape.cx;
        var y = shape.cy;
        var a = shape.rx;
        var b = shape.ry;
        var ox = a * k;
        var oy = b * 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 + oy, x + ox, y + b, x, y + b);
        ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);
        ctx.closePath();
    };
    return Ellipse;
}(graphic_Path));
Ellipse.prototype.type = 'ellipse';
/* harmony default export */ const shape_Ellipse = (Ellipse);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/roundSector.js

var roundSector_PI = Math.PI;
var roundSector_PI2 = roundSector_PI * 2;
var roundSector_mathSin = Math.sin;
var roundSector_mathCos = Math.cos;
var mathACos = Math.acos;
var mathATan2 = Math.atan2;
var roundSector_mathAbs = Math.abs;
var roundSector_mathSqrt = Math.sqrt;
var roundSector_mathMax = Math.max;
var roundSector_mathMin = Math.min;
var e = 1e-4;
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
    var x10 = x1 - x0;
    var y10 = y1 - y0;
    var x32 = x3 - x2;
    var y32 = y3 - y2;
    var t = y32 * x10 - x32 * y10;
    if (t * t < e) {
        return;
    }
    t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
    return [x0 + t * x10, y0 + t * y10];
}
function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
    var x01 = x0 - x1;
    var y01 = y0 - y1;
    var lo = (clockwise ? cr : -cr) / roundSector_mathSqrt(x01 * x01 + y01 * y01);
    var ox = lo * y01;
    var oy = -lo * x01;
    var x11 = x0 + ox;
    var y11 = y0 + oy;
    var x10 = x1 + ox;
    var y10 = y1 + oy;
    var x00 = (x11 + x10) / 2;
    var y00 = (y11 + y10) / 2;
    var dx = x10 - x11;
    var dy = y10 - y11;
    var d2 = dx * dx + dy * dy;
    var r = radius - cr;
    var s = x11 * y10 - x10 * y11;
    var d = (dy < 0 ? -1 : 1) * roundSector_mathSqrt(roundSector_mathMax(0, r * r * d2 - s * s));
    var cx0 = (s * dy - dx * d) / d2;
    var cy0 = (-s * dx - dy * d) / d2;
    var cx1 = (s * dy + dx * d) / d2;
    var cy1 = (-s * dx + dy * d) / d2;
    var dx0 = cx0 - x00;
    var dy0 = cy0 - y00;
    var dx1 = cx1 - x00;
    var dy1 = cy1 - y00;
    if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) {
        cx0 = cx1;
        cy0 = cy1;
    }
    return {
        cx: cx0,
        cy: cy0,
        x01: -ox,
        y01: -oy,
        x11: cx0 * (radius / r - 1),
        y11: cy0 * (radius / r - 1)
    };
}
function roundSector_buildPath(ctx, shape) {
    var radius = roundSector_mathMax(shape.r, 0);
    var innerRadius = roundSector_mathMax(shape.r0 || 0, 0);
    var hasRadius = radius > 0;
    var hasInnerRadius = innerRadius > 0;
    if (!hasRadius && !hasInnerRadius) {
        return;
    }
    if (!hasRadius) {
        radius = innerRadius;
        innerRadius = 0;
    }
    if (innerRadius > radius) {
        var tmp = radius;
        radius = innerRadius;
        innerRadius = tmp;
    }
    var clockwise = !!shape.clockwise;
    var startAngle = shape.startAngle;
    var endAngle = shape.endAngle;
    var arc;
    if (startAngle === endAngle) {
        arc = 0;
    }
    else {
        var tmpAngles = [startAngle, endAngle];
        normalizeArcAngles(tmpAngles, !clockwise);
        arc = roundSector_mathAbs(tmpAngles[0] - tmpAngles[1]);
    }
    var x = shape.cx;
    var y = shape.cy;
    var cornerRadius = shape.cornerRadius || 0;
    var innerCornerRadius = shape.innerCornerRadius || 0;
    if (!(radius > e)) {
        ctx.moveTo(x, y);
    }
    else if (arc > roundSector_PI2 - e) {
        ctx.moveTo(x + radius * roundSector_mathCos(startAngle), y + radius * roundSector_mathSin(startAngle));
        ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
        if (innerRadius > e) {
            ctx.moveTo(x + innerRadius * roundSector_mathCos(endAngle), y + innerRadius * roundSector_mathSin(endAngle));
            ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
        }
    }
    else {
        var halfRd = roundSector_mathAbs(radius - innerRadius) / 2;
        var cr = roundSector_mathMin(halfRd, cornerRadius);
        var icr = roundSector_mathMin(halfRd, innerCornerRadius);
        var cr0 = icr;
        var cr1 = cr;
        var xrs = radius * roundSector_mathCos(startAngle);
        var yrs = radius * roundSector_mathSin(startAngle);
        var xire = innerRadius * roundSector_mathCos(endAngle);
        var yire = innerRadius * roundSector_mathSin(endAngle);
        var xre = void 0;
        var yre = void 0;
        var xirs = void 0;
        var yirs = void 0;
        if (cr > e || icr > e) {
            xre = radius * roundSector_mathCos(endAngle);
            yre = radius * roundSector_mathSin(endAngle);
            xirs = innerRadius * roundSector_mathCos(startAngle);
            yirs = innerRadius * roundSector_mathSin(startAngle);
            if (arc < roundSector_PI) {
                var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
                if (it_1) {
                    var x0 = xrs - it_1[0];
                    var y0 = yrs - it_1[1];
                    var x1 = xre - it_1[0];
                    var y1 = yre - it_1[1];
                    var a = 1 / roundSector_mathSin(mathACos((x0 * x1 + y0 * y1) / (roundSector_mathSqrt(x0 * x0 + y0 * y0) * roundSector_mathSqrt(x1 * x1 + y1 * y1))) / 2);
                    var b = roundSector_mathSqrt(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
                    cr0 = roundSector_mathMin(icr, (innerRadius - b) / (a - 1));
                    cr1 = roundSector_mathMin(cr, (radius - b) / (a + 1));
                }
            }
        }
        if (!(arc > e)) {
            ctx.moveTo(x + xrs, y + yrs);
        }
        else if (cr1 > e) {
            var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, cr1, clockwise);
            var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, cr1, clockwise);
            ctx.moveTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
            if (cr1 < cr) {
                ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
            }
            else {
                ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
                ctx.arc(x, y, radius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), !clockwise);
                ctx.arc(x + ct1.cx, y + ct1.cy, cr1, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
            }
        }
        else {
            ctx.moveTo(x + xrs, y + yrs);
            ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
        }
        if (!(innerRadius > e) || !(arc > e)) {
            ctx.lineTo(x + xire, y + yire);
        }
        else if (cr0 > e) {
            var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -cr0, clockwise);
            var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -cr0, clockwise);
            ctx.lineTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
            if (cr0 < icr) {
                ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
            }
            else {
                ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
                ctx.arc(x, y, innerRadius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), clockwise);
                ctx.arc(x + ct1.cx, y + ct1.cy, cr0, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
            }
        }
        else {
            ctx.lineTo(x + xire, y + yire);
            ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
        }
    }
    ctx.closePath();
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Sector.js



var SectorShape = (function () {
    function SectorShape() {
        this.cx = 0;
        this.cy = 0;
        this.r0 = 0;
        this.r = 0;
        this.startAngle = 0;
        this.endAngle = Math.PI * 2;
        this.clockwise = true;
        this.cornerRadius = 0;
        this.innerCornerRadius = 0;
    }
    return SectorShape;
}());

var Sector = (function (_super) {
    __extends(Sector, _super);
    function Sector(opts) {
        return _super.call(this, opts) || this;
    }
    Sector.prototype.getDefaultShape = function () {
        return new SectorShape();
    };
    Sector.prototype.buildPath = function (ctx, shape) {
        roundSector_buildPath(ctx, shape);
    };
    Sector.prototype.isZeroArea = function () {
        return this.shape.startAngle === this.shape.endAngle
            || this.shape.r === this.shape.r0;
    };
    return Sector;
}(graphic_Path));
Sector.prototype.type = 'sector';
/* harmony default export */ const shape_Sector = (Sector);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Ring.js


var RingShape = (function () {
    function RingShape() {
        this.cx = 0;
        this.cy = 0;
        this.r = 0;
        this.r0 = 0;
    }
    return RingShape;
}());

var Ring = (function (_super) {
    __extends(Ring, _super);
    function Ring(opts) {
        return _super.call(this, opts) || this;
    }
    Ring.prototype.getDefaultShape = function () {
        return new RingShape();
    };
    Ring.prototype.buildPath = function (ctx, shape) {
        var x = shape.cx;
        var y = shape.cy;
        var PI2 = Math.PI * 2;
        ctx.moveTo(x + shape.r, y);
        ctx.arc(x, y, shape.r, 0, PI2, false);
        ctx.moveTo(x + shape.r0, y);
        ctx.arc(x, y, shape.r0, 0, PI2, true);
    };
    return Ring;
}(graphic_Path));
Ring.prototype.type = 'ring';
/* harmony default export */ const shape_Ring = (Ring);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/smoothSpline.js

function interpolate(p0, p1, p2, p3, t, t2, t3) {
    var v0 = (p2 - p0) * 0.5;
    var v1 = (p3 - p1) * 0.5;
    return (2 * (p1 - p2) + v0 + v1) * t3
        + (-3 * (p1 - p2) - 2 * v0 - v1) * t2
        + v0 * t + p1;
}
function smoothSpline(points, isLoop) {
    var len = points.length;
    var ret = [];
    var distance = 0;
    for (var i = 1; i < len; i++) {
        distance += vector_distance(points[i - 1], points[i]);
    }
    var segs = distance / 2;
    segs = segs < len ? len : segs;
    for (var i = 0; i < segs; i++) {
        var pos = i / (segs - 1) * (isLoop ? len : len - 1);
        var idx = Math.floor(pos);
        var w = pos - idx;
        var p0 = void 0;
        var p1 = points[idx % len];
        var p2 = void 0;
        var p3 = void 0;
        if (!isLoop) {
            p0 = points[idx === 0 ? idx : idx - 1];
            p2 = points[idx > len - 2 ? len - 1 : idx + 1];
            p3 = points[idx > len - 3 ? len - 1 : idx + 2];
        }
        else {
            p0 = points[(idx - 1 + len) % len];
            p2 = points[(idx + 1) % len];
            p3 = points[(idx + 2) % len];
        }
        var w2 = w * w;
        var w3 = w * w2;
        ret.push([
            interpolate(p0[0], p1[0], p2[0], p3[0], w, w2, w3),
            interpolate(p0[1], p1[1], p2[1], p3[1], w, w2, w3)
        ]);
    }
    return ret;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/smoothBezier.js

function smoothBezier(points, smooth, isLoop, constraint) {
    var cps = [];
    var v = [];
    var v1 = [];
    var v2 = [];
    var prevPoint;
    var nextPoint;
    var min;
    var max;
    if (constraint) {
        min = [Infinity, Infinity];
        max = [-Infinity, -Infinity];
        for (var i = 0, len = points.length; i < len; i++) {
            vector_min(min, min, points[i]);
            vector_max(max, max, points[i]);
        }
        vector_min(min, min, constraint[0]);
        vector_max(max, max, constraint[1]);
    }
    for (var i = 0, len = points.length; i < len; i++) {
        var point = points[i];
        if (isLoop) {
            prevPoint = points[i ? i - 1 : len - 1];
            nextPoint = points[(i + 1) % len];
        }
        else {
            if (i === 0 || i === len - 1) {
                cps.push(vector_clone(points[i]));
                continue;
            }
            else {
                prevPoint = points[i - 1];
                nextPoint = points[i + 1];
            }
        }
        sub(v, nextPoint, prevPoint);
        vector_scale(v, v, smooth);
        var d0 = vector_distance(point, prevPoint);
        var d1 = vector_distance(point, nextPoint);
        var sum = d0 + d1;
        if (sum !== 0) {
            d0 /= sum;
            d1 /= sum;
        }
        vector_scale(v1, v, -d0);
        vector_scale(v2, v, d1);
        var cp0 = add([], point, v1);
        var cp1 = add([], point, v2);
        if (constraint) {
            vector_max(cp0, cp0, min);
            vector_min(cp0, cp0, max);
            vector_max(cp1, cp1, min);
            vector_min(cp1, cp1, max);
        }
        cps.push(cp0);
        cps.push(cp1);
    }
    if (isLoop) {
        cps.push(cps.shift());
    }
    return cps;
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/helper/poly.js


function poly_buildPath(ctx, shape, closePath) {
    var smooth = shape.smooth;
    var points = shape.points;
    if (points && points.length >= 2) {
        if (smooth && smooth !== 'spline') {
            var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint);
            ctx.moveTo(points[0][0], points[0][1]);
            var len = points.length;
            for (var i = 0; i < (closePath ? len : len - 1); i++) {
                var cp1 = controlPoints[i * 2];
                var cp2 = controlPoints[i * 2 + 1];
                var p = points[(i + 1) % len];
                ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]);
            }
        }
        else {
            if (smooth === 'spline') {
                points = smoothSpline(points, closePath);
            }
            ctx.moveTo(points[0][0], points[0][1]);
            for (var i = 1, l = points.length; i < l; i++) {
                ctx.lineTo(points[i][0], points[i][1]);
            }
        }
        closePath && ctx.closePath();
    }
}

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Polygon.js



var PolygonShape = (function () {
    function PolygonShape() {
        this.points = null;
        this.smooth = 0;
        this.smoothConstraint = null;
    }
    return PolygonShape;
}());

var Polygon = (function (_super) {
    __extends(Polygon, _super);
    function Polygon(opts) {
        return _super.call(this, opts) || this;
    }
    Polygon.prototype.getDefaultShape = function () {
        return new PolygonShape();
    };
    Polygon.prototype.buildPath = function (ctx, shape) {
        poly_buildPath(ctx, shape, true);
    };
    return Polygon;
}(graphic_Path));
;
Polygon.prototype.type = 'polygon';
/* harmony default export */ const shape_Polygon = (Polygon);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Polyline.js



var PolylineShape = (function () {
    function PolylineShape() {
        this.points = null;
        this.percent = 1;
        this.smooth = 0;
        this.smoothConstraint = null;
    }
    return PolylineShape;
}());

var Polyline = (function (_super) {
    __extends(Polyline, _super);
    function Polyline(opts) {
        return _super.call(this, opts) || this;
    }
    Polyline.prototype.getDefaultStyle = function () {
        return {
            stroke: '#000',
            fill: null
        };
    };
    Polyline.prototype.getDefaultShape = function () {
        return new PolylineShape();
    };
    Polyline.prototype.buildPath = function (ctx, shape) {
        poly_buildPath(ctx, shape, false);
    };
    return Polyline;
}(graphic_Path));
Polyline.prototype.type = 'polyline';
/* harmony default export */ const shape_Polyline = (Polyline);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Line.js



var Line_subPixelOptimizeOutputShape = {};
var LineShape = (function () {
    function LineShape() {
        this.x1 = 0;
        this.y1 = 0;
        this.x2 = 0;
        this.y2 = 0;
        this.percent = 1;
    }
    return LineShape;
}());

var Line = (function (_super) {
    __extends(Line, _super);
    function Line(opts) {
        return _super.call(this, opts) || this;
    }
    Line.prototype.getDefaultStyle = function () {
        return {
            stroke: '#000',
            fill: null
        };
    };
    Line.prototype.getDefaultShape = function () {
        return new LineShape();
    };
    Line.prototype.buildPath = function (ctx, shape) {
        var x1;
        var y1;
        var x2;
        var y2;
        if (this.subPixelOptimize) {
            var optimizedShape = subPixelOptimizeLine(Line_subPixelOptimizeOutputShape, shape, this.style);
            x1 = optimizedShape.x1;
            y1 = optimizedShape.y1;
            x2 = optimizedShape.x2;
            y2 = optimizedShape.y2;
        }
        else {
            x1 = shape.x1;
            y1 = shape.y1;
            x2 = shape.x2;
            y2 = shape.y2;
        }
        var percent = shape.percent;
        if (percent === 0) {
            return;
        }
        ctx.moveTo(x1, y1);
        if (percent < 1) {
            x2 = x1 * (1 - percent) + x2 * percent;
            y2 = y1 * (1 - percent) + y2 * percent;
        }
        ctx.lineTo(x2, y2);
    };
    Line.prototype.pointAt = function (p) {
        var shape = this.shape;
        return [
            shape.x1 * (1 - p) + shape.x2 * p,
            shape.y1 * (1 - p) + shape.y2 * p
        ];
    };
    return Line;
}(graphic_Path));
Line.prototype.type = 'line';
/* harmony default export */ const shape_Line = (Line);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/BezierCurve.js




var out = [];
var BezierCurveShape = (function () {
    function BezierCurveShape() {
        this.x1 = 0;
        this.y1 = 0;
        this.x2 = 0;
        this.y2 = 0;
        this.cpx1 = 0;
        this.cpy1 = 0;
        this.percent = 1;
    }
    return BezierCurveShape;
}());

function someVectorAt(shape, t, isTangent) {
    var cpx2 = shape.cpx2;
    var cpy2 = shape.cpy2;
    if (cpx2 === null || cpy2 === null) {
        return [
            (isTangent ? cubicDerivativeAt : curve_cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t),
            (isTangent ? cubicDerivativeAt : curve_cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)
        ];
    }
    else {
        return [
            (isTangent ? quadraticDerivativeAt : curve_quadraticAt)(shape.x1, shape.cpx1, shape.x2, t),
            (isTangent ? quadraticDerivativeAt : curve_quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)
        ];
    }
}
var BezierCurve = (function (_super) {
    __extends(BezierCurve, _super);
    function BezierCurve(opts) {
        return _super.call(this, opts) || this;
    }
    BezierCurve.prototype.getDefaultStyle = function () {
        return {
            stroke: '#000',
            fill: null
        };
    };
    BezierCurve.prototype.getDefaultShape = function () {
        return new BezierCurveShape();
    };
    BezierCurve.prototype.buildPath = function (ctx, shape) {
        var x1 = shape.x1;
        var y1 = shape.y1;
        var x2 = shape.x2;
        var y2 = shape.y2;
        var cpx1 = shape.cpx1;
        var cpy1 = shape.cpy1;
        var cpx2 = shape.cpx2;
        var cpy2 = shape.cpy2;
        var percent = shape.percent;
        if (percent === 0) {
            return;
        }
        ctx.moveTo(x1, y1);
        if (cpx2 == null || cpy2 == null) {
            if (percent < 1) {
                quadraticSubdivide(x1, cpx1, x2, percent, out);
                cpx1 = out[1];
                x2 = out[2];
                quadraticSubdivide(y1, cpy1, y2, percent, out);
                cpy1 = out[1];
                y2 = out[2];
            }
            ctx.quadraticCurveTo(cpx1, cpy1, x2, y2);
        }
        else {
            if (percent < 1) {
                cubicSubdivide(x1, cpx1, cpx2, x2, percent, out);
                cpx1 = out[1];
                cpx2 = out[2];
                x2 = out[3];
                cubicSubdivide(y1, cpy1, cpy2, y2, percent, out);
                cpy1 = out[1];
                cpy2 = out[2];
                y2 = out[3];
            }
            ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2);
        }
    };
    BezierCurve.prototype.pointAt = function (t) {
        return someVectorAt(this.shape, t, false);
    };
    BezierCurve.prototype.tangentAt = function (t) {
        var p = someVectorAt(this.shape, t, true);
        return normalize(p, p);
    };
    return BezierCurve;
}(graphic_Path));
;
BezierCurve.prototype.type = 'bezier-curve';
/* harmony default export */ const shape_BezierCurve = (BezierCurve);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/shape/Arc.js


var ArcShape = (function () {
    function ArcShape() {
        this.cx = 0;
        this.cy = 0;
        this.r = 0;
        this.startAngle = 0;
        this.endAngle = Math.PI * 2;
        this.clockwise = true;
    }
    return ArcShape;
}());

var Arc = (function (_super) {
    __extends(Arc, _super);
    function Arc(opts) {
        return _super.call(this, opts) || this;
    }
    Arc.prototype.getDefaultStyle = function () {
        return {
            stroke: '#000',
            fill: null
        };
    };
    Arc.prototype.getDefaultShape = function () {
        return new ArcShape();
    };
    Arc.prototype.buildPath = function (ctx, shape) {
        var x = shape.cx;
        var y = shape.cy;
        var r = Math.max(shape.r, 0);
        var startAngle = shape.startAngle;
        var endAngle = shape.endAngle;
        var clockwise = shape.clockwise;
        var unitX = Math.cos(startAngle);
        var unitY = Math.sin(startAngle);
        ctx.moveTo(unitX * r + x, unitY * r + y);
        ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
    };
    return Arc;
}(graphic_Path));
Arc.prototype.type = 'arc';
/* harmony default export */ const shape_Arc = (Arc);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/CompoundPath.js


var CompoundPath = (function (_super) {
    __extends(CompoundPath, _super);
    function CompoundPath() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.type = 'compound';
        return _this;
    }
    CompoundPath.prototype._updatePathDirty = function () {
        var paths = this.shape.paths;
        var dirtyPath = this.shapeChanged();
        for (var i = 0; i < paths.length; i++) {
            dirtyPath = dirtyPath || paths[i].shapeChanged();
        }
        if (dirtyPath) {
            this.dirtyShape();
        }
    };
    CompoundPath.prototype.beforeBrush = function () {
        this._updatePathDirty();
        var paths = this.shape.paths || [];
        var scale = this.getGlobalScale();
        for (var i = 0; i < paths.length; i++) {
            if (!paths[i].path) {
                paths[i].createPathProxy();
            }
            paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold);
        }
    };
    CompoundPath.prototype.buildPath = function (ctx, shape) {
        var paths = shape.paths || [];
        for (var i = 0; i < paths.length; i++) {
            paths[i].buildPath(ctx, paths[i].shape, true);
        }
    };
    CompoundPath.prototype.afterBrush = function () {
        var paths = this.shape.paths || [];
        for (var i = 0; i < paths.length; i++) {
            paths[i].pathUpdated();
        }
    };
    CompoundPath.prototype.getBoundingRect = function () {
        this._updatePathDirty.call(this);
        return graphic_Path.prototype.getBoundingRect.call(this);
    };
    return CompoundPath;
}(graphic_Path));
/* harmony default export */ const graphic_CompoundPath = (CompoundPath);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/Gradient.js
var Gradient = (function () {
    function Gradient(colorStops) {
        this.colorStops = colorStops || [];
    }
    Gradient.prototype.addColorStop = function (offset, color) {
        this.colorStops.push({
            offset: offset,
            color: color
        });
    };
    return Gradient;
}());
/* harmony default export */ const graphic_Gradient = (Gradient);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/LinearGradient.js


var LinearGradient = (function (_super) {
    __extends(LinearGradient, _super);
    function LinearGradient(x, y, x2, y2, colorStops, globalCoord) {
        var _this = _super.call(this, colorStops) || this;
        _this.x = x == null ? 0 : x;
        _this.y = y == null ? 0 : y;
        _this.x2 = x2 == null ? 1 : x2;
        _this.y2 = y2 == null ? 0 : y2;
        _this.type = 'linear';
        _this.global = globalCoord || false;
        return _this;
    }
    return LinearGradient;
}(graphic_Gradient));
/* harmony default export */ const graphic_LinearGradient = (LinearGradient);
;

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/RadialGradient.js


var RadialGradient = (function (_super) {
    __extends(RadialGradient, _super);
    function RadialGradient(x, y, r, colorStops, globalCoord) {
        var _this = _super.call(this, colorStops) || this;
        _this.x = x == null ? 0.5 : x;
        _this.y = y == null ? 0.5 : y;
        _this.r = r == null ? 0.5 : r;
        _this.type = 'radial';
        _this.global = globalCoord || false;
        return _this;
    }
    return RadialGradient;
}(graphic_Gradient));
/* harmony default export */ const graphic_RadialGradient = (RadialGradient);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/core/OrientedBoundingRect.js

var extent = [0, 0];
var extent2 = [0, 0];
var OrientedBoundingRect_minTv = new core_Point();
var OrientedBoundingRect_maxTv = new core_Point();
var OrientedBoundingRect = (function () {
    function OrientedBoundingRect(rect, transform) {
        this._corners = [];
        this._axes = [];
        this._origin = [0, 0];
        for (var i = 0; i < 4; i++) {
            this._corners[i] = new core_Point();
        }
        for (var i = 0; i < 2; i++) {
            this._axes[i] = new core_Point();
        }
        if (rect) {
            this.fromBoundingRect(rect, transform);
        }
    }
    OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) {
        var corners = this._corners;
        var axes = this._axes;
        var x = rect.x;
        var y = rect.y;
        var x2 = x + rect.width;
        var y2 = y + rect.height;
        corners[0].set(x, y);
        corners[1].set(x2, y);
        corners[2].set(x2, y2);
        corners[3].set(x, y2);
        if (transform) {
            for (var i = 0; i < 4; i++) {
                corners[i].transform(transform);
            }
        }
        core_Point.sub(axes[0], corners[1], corners[0]);
        core_Point.sub(axes[1], corners[3], corners[0]);
        axes[0].normalize();
        axes[1].normalize();
        for (var i = 0; i < 2; i++) {
            this._origin[i] = axes[i].dot(corners[0]);
        }
    };
    OrientedBoundingRect.prototype.intersect = function (other, mtv) {
        var overlapped = true;
        var noMtv = !mtv;
        OrientedBoundingRect_minTv.set(Infinity, Infinity);
        OrientedBoundingRect_maxTv.set(0, 0);
        if (!this._intersectCheckOneSide(this, other, OrientedBoundingRect_minTv, OrientedBoundingRect_maxTv, noMtv, 1)) {
            overlapped = false;
            if (noMtv) {
                return overlapped;
            }
        }
        if (!this._intersectCheckOneSide(other, this, OrientedBoundingRect_minTv, OrientedBoundingRect_maxTv, noMtv, -1)) {
            overlapped = false;
            if (noMtv) {
                return overlapped;
            }
        }
        if (!noMtv) {
            core_Point.copy(mtv, overlapped ? OrientedBoundingRect_minTv : OrientedBoundingRect_maxTv);
        }
        return overlapped;
    };
    OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, minTv, maxTv, noMtv, inverse) {
        var overlapped = true;
        for (var i = 0; i < 2; i++) {
            var axis = this._axes[i];
            this._getProjMinMaxOnAxis(i, self._corners, extent);
            this._getProjMinMaxOnAxis(i, other._corners, extent2);
            if (extent[1] < extent2[0] || extent[0] > extent2[1]) {
                overlapped = false;
                if (noMtv) {
                    return overlapped;
                }
                var dist0 = Math.abs(extent2[0] - extent[1]);
                var dist1 = Math.abs(extent[0] - extent2[1]);
                if (Math.min(dist0, dist1) > maxTv.len()) {
                    if (dist0 < dist1) {
                        core_Point.scale(maxTv, axis, -dist0 * inverse);
                    }
                    else {
                        core_Point.scale(maxTv, axis, dist1 * inverse);
                    }
                }
            }
            else if (minTv) {
                var dist0 = Math.abs(extent2[0] - extent[1]);
                var dist1 = Math.abs(extent[0] - extent2[1]);
                if (Math.min(dist0, dist1) < minTv.len()) {
                    if (dist0 < dist1) {
                        core_Point.scale(minTv, axis, dist0 * inverse);
                    }
                    else {
                        core_Point.scale(minTv, axis, -dist1 * inverse);
                    }
                }
            }
        }
        return overlapped;
    };
    OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) {
        var axis = this._axes[dim];
        var origin = this._origin;
        var proj = corners[0].dot(axis) + origin[dim];
        var min = proj;
        var max = proj;
        for (var i = 1; i < corners.length; i++) {
            var proj_1 = corners[i].dot(axis) + origin[dim];
            min = Math.min(proj_1, min);
            max = Math.max(proj_1, max);
        }
        out[0] = min;
        out[1] = max;
    };
    return OrientedBoundingRect;
}());
/* harmony default export */ const core_OrientedBoundingRect = (OrientedBoundingRect);

;// CONCATENATED MODULE: ./node_modules/zrender/lib/graphic/IncrementalDisplayable.js



var m = [];
var IncrementalDisplayable = (function (_super) {
    __extends(IncrementalDisplayable, _super);
    function IncrementalDisplayable() {
        var _this = _super !== null && _super.apply(this, arguments) || this;
        _this.notClear = true;
        _this.incremental = true;
        _this._displayables = [];
        _this._temporaryDisplayables = [];
        _this._cursor = 0;
        return _this;
    }
    IncrementalDisplayable.prototype.traverse = function (cb, context) {
        cb.call(context, this);
    };
    IncrementalDisplayable.prototype.useStyle = function () {
        this.style = {};
    };
    IncrementalDisplayable.prototype.getCursor = function () {
        return this._cursor;
    };
    IncrementalDisplayable.prototype.innerAfterBrush = function () {
        this._cursor = this._displayables.length;
    };
    IncrementalDisplayable.prototype.clearDisplaybles = function () {
        this._displayables = [];
        this._temporaryDisplayables = [];
        this._cursor = 0;
        this.markRedraw();
        this.notClear = false;
    };
    IncrementalDisplayable.prototype.clearTemporalDisplayables = function () {
        this._temporaryDisplayables = [];
    };
    IncrementalDisplayable.prototype.addDisplayable = function (displayable, notPersistent) {
        if (notPersistent) {
            this._temporaryDisplayables.push(displayable);
        }
        else {
            this._displayables.push(displayable);
        }
        this.markRedraw();
    };
    IncrementalDisplayable.prototype.addDisplayables = function (displayables, notPersistent) {
        notPersistent = notPersistent || false;
        for (var i = 0; i < displayables.length; i++) {
            this.addDisplayable(displayables[i], notPersistent);
        }
    };
    IncrementalDisplayable.prototype.getDisplayables = function () {
        return this._displayables;
    };
    IncrementalDisplayable.prototype.getTemporalDisplayables = function () {
        return this._temporaryDisplayables;
    };
    IncrementalDisplayable.prototype.eachPendingDisplayable = function (cb) {
        for (var i = this._cursor; i < this._displayables.length; i++) {
            cb && cb(this._displayables[i]);
        }
        for (var i = 0; i < this._temporaryDisplayables.length; i++) {
            cb && cb(this._temporaryDisplayables[i]);
        }
    };
    IncrementalDisplayable.prototype.update = function () {
        this.updateTransform();
        for (var i = this._cursor; i < this._displayables.length; i++) {
            var displayable = this._displayables[i];
            displayable.parent = this;
            displayable.update();
            displayable.parent = null;
        }
        for (var i = 0; i < this._temporaryDisplayables.length; i++) {
            var displayable = this._temporaryDisplayables[i];
            displayable.parent = this;
            displayable.update();
            displayable.parent = null;
        }
    };
    IncrementalDisplayable.prototype.getBoundingRect = function () {
        if (!this._rect) {
            var rect = new core_BoundingRect(Infinity, Infinity, -Infinity, -Infinity);
            for (var i = 0; i < this._displayables.length; i++) {
                var displayable = this._displayables[i];
                var childRect = displayable.getBoundingRect().clone();
                if (displayable.needLocalTransform()) {
                    childRect.applyTransform(displayable.getLocalTransform(m));
                }
                rect.union(childRect);
            }
            this._rect = rect;
        }
        return this._rect;
    };
    IncrementalDisplayable.prototype.contain = function (x, y) {
        var localPos = this.transformCoordToLocal(x, y);
        var rect = this.getBoundingRect();
        if (rect.contain(localPos[0], localPos[1])) {
            for (var i = 0; i < this._displayables.length; i++) {
                var displayable = this._displayables[i];
                if (displayable.contain(x, y)) {
                    return true;
                }
            }
        }
        return false;
    };
    return IncrementalDisplayable;
}(graphic_Displayable));
/* harmony default export */ const graphic_IncrementalDisplayable = (IncrementalDisplayable);

;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/graphic.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/




























var graphic_mathMax = Math.max;
var graphic_mathMin = Math.min;
var _customShapeMap = {};
/**
 * Extend shape with parameters
 */

function extendShape(opts) {
  return graphic_Path.extend(opts);
}
var extendPathFromString = extendFromString;
/**
 * Extend path
 */

function extendPath(pathData, opts) {
  return extendPathFromString(pathData, opts);
}
/**
 * Register a user defined shape.
 * The shape class can be fetched by `getShapeClass`
 * This method will overwrite the registered shapes, including
 * the registered built-in shapes, if using the same `name`.
 * The shape can be used in `custom series` and
 * `graphic component` by declaring `{type: name}`.
 *
 * @param name
 * @param ShapeClass Can be generated by `extendShape`.
 */

function registerShape(name, ShapeClass) {
  _customShapeMap[name] = ShapeClass;
}
/**
 * Find shape class registered by `registerShape`. Usually used in
 * fetching user defined shape.
 *
 * [Caution]:
 * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared
 * to use user registered shapes.
 * Because the built-in shape (see `getBuiltInShape`) will be registered by
 * `registerShape` by default. That enables users to get both built-in
 * shapes as well as the shapes belonging to themsleves. But users can overwrite
 * the built-in shapes by using names like 'circle', 'rect' via calling
 * `registerShape`. So the echarts inner featrues should not fetch shapes from here
 * in case that it is overwritten by users, except that some features, like
 * `custom series`, `graphic component`, do it deliberately.
 *
 * (2) In the features like `custom series`, `graphic component`, the user input
 * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic
 * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names
 * are reserved names, that is, if some user register a shape named `'image'`,
 * the shape will not be used. If we intending to add some more reserved names
 * in feature, that might bring break changes (disable some existing user shape
 * names). But that case probably rearly happen. So we dont make more mechanism
 * to resolve this issue here.
 *
 * @param name
 * @return The shape class. If not found, return nothing.
 */

function getShapeClass(name) {
  if (_customShapeMap.hasOwnProperty(name)) {
    return _customShapeMap[name];
  }
}
/**
 * Create a path element from path data string
 * @param pathData
 * @param opts
 * @param rect
 * @param layout 'center' or 'cover' default to be cover
 */

function makePath(pathData, opts, rect, layout) {
  var path = createFromString(pathData, opts);

  if (rect) {
    if (layout === 'center') {
      rect = centerGraphic(rect, path.getBoundingRect());
    }

    resizePath(path, rect);
  }

  return path;
}
/**
 * Create a image element from image url
 * @param imageUrl image url
 * @param opts options
 * @param rect constrain rect
 * @param layout 'center' or 'cover'. Default to be 'cover'
 */

function makeImage(imageUrl, rect, layout) {
  var zrImg = new graphic_Image({
    style: {
      image: imageUrl,
      x: rect.x,
      y: rect.y,
      width: rect.width,
      height: rect.height
    },
    onload: function (img) {
      if (layout === 'center') {
        var boundingRect = {
          width: img.width,
          height: img.height
        };
        zrImg.setStyle(centerGraphic(rect, boundingRect));
      }
    }
  });
  return zrImg;
}
/**
 * Get position of centered element in bounding box.
 *
 * @param  rect         element local bounding box
 * @param  boundingRect constraint bounding box
 * @return element position containing x, y, width, and height
 */

function centerGraphic(rect, boundingRect) {
  // Set rect to center, keep width / height ratio.
  var aspect = boundingRect.width / boundingRect.height;
  var width = rect.height * aspect;
  var height;

  if (width <= rect.width) {
    height = rect.height;
  } else {
    width = rect.width;
    height = width / aspect;
  }

  var cx = rect.x + rect.width / 2;
  var cy = rect.y + rect.height / 2;
  return {
    x: cx - width / 2,
    y: cy - height / 2,
    width: width,
    height: height
  };
}

var graphic_mergePath = mergePath;
/**
 * Resize a path to fit the rect
 * @param path
 * @param rect
 */

function resizePath(path, rect) {
  if (!path.applyTransform) {
    return;
  }

  var pathRect = path.getBoundingRect();
  var m = pathRect.calculateTransform(rect);
  path.applyTransform(m);
}
/**
 * Sub pixel optimize line for canvas
 */

function graphic_subPixelOptimizeLine(param) {
  subPixelOptimizeLine(param.shape, param.shape, param.style);
  return param;
}
/**
 * Sub pixel optimize rect for canvas
 */

function graphic_subPixelOptimizeRect(param) {
  subPixelOptimizeRect(param.shape, param.shape, param.style);
  return param;
}
/**
 * Sub pixel optimize for canvas
 *
 * @param position Coordinate, such as x, y
 * @param lineWidth Should be nonnegative integer.
 * @param positiveOrNegative Default false (negative).
 * @return Optimized position.
 */

var graphic_subPixelOptimize = subPixelOptimize;

function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) {
  var isFrom = false;
  var removeOpt;

  if (typeof dataIndex === 'function') {
    during = cb;
    cb = dataIndex;
    dataIndex = null;
  } else if (isObject(dataIndex)) {
    cb = dataIndex.cb;
    during = dataIndex.during;
    isFrom = dataIndex.isFrom;
    removeOpt = dataIndex.removeOpt;
    dataIndex = dataIndex.dataIndex;
  }

  var isUpdate = animationType === 'update';
  var isRemove = animationType === 'remove';
  var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option.
  // If animation is enabled. Will use this animation config in payload.
  // If animation is disabled. Just ignore it.

  if (animatableModel && animatableModel.ecModel) {
    var updatePayload = animatableModel.ecModel.getUpdatePayload();
    animationPayload = updatePayload && updatePayload.animation;
  }

  var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();

  if (!isRemove) {
    // Must stop the remove animation.
    el.stopAnimation('remove');
  }

  if (animationEnabled) {
    var duration = void 0;
    var animationEasing = void 0;
    var animationDelay = void 0;

    if (animationPayload) {
      duration = animationPayload.duration || 0;
      animationEasing = animationPayload.easing || 'cubicOut';
      animationDelay = animationPayload.delay || 0;
    } else if (isRemove) {
      removeOpt = removeOpt || {};
      duration = retrieve2(removeOpt.duration, 200);
      animationEasing = retrieve2(removeOpt.easing, 'cubicOut');
      animationDelay = 0;
    } else {
      duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration');
      animationEasing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing');
      animationDelay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay');
    }

    if (typeof animationDelay === 'function') {
      animationDelay = animationDelay(dataIndex, animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);
    }

    if (typeof duration === 'function') {
      duration = duration(dataIndex);
    }

    duration > 0 ? isFrom ? el.animateFrom(props, {
      duration: duration,
      delay: animationDelay || 0,
      easing: animationEasing,
      done: cb,
      force: !!cb || !!during,
      scope: animationType,
      during: during
    }) : el.animateTo(props, {
      duration: duration,
      delay: animationDelay || 0,
      easing: animationEasing,
      done: cb,
      force: !!cb || !!during,
      setToFinal: true,
      scope: animationType,
      during: during
    }) : ( // FIXME:
    // If `duration` is 0, only the animation on props
    // can be stoped, other animation should be continued?
    // But at present using duration 0 in `animateTo`, `animateFrom`
    // might cause unexpected behavior.
    el.stopAnimation(), // If `isFrom`, the props is the "from" props.
    !isFrom && el.attr(props), cb && cb());
  } else {
    el.stopAnimation();
    !isFrom && el.attr(props); // Call during once.

    during && during(1);
    cb && cb();
  }
}
/**
 * Update graphic element properties with or without animation according to the
 * configuration in series.
 *
 * Caution: this method will stop previous animation.
 * So do not use this method to one element twice before
 * animation starts, unless you know what you are doing.
 * @example
 *     graphic.updateProps(el, {
 *         position: [100, 100]
 *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });
 *     // Or
 *     graphic.updateProps(el, {
 *         position: [100, 100]
 *     }, seriesModel, function () { console.log('Animation done!'); });
 */


function updateProps(el, props, // TODO: TYPE AnimatableModel
animatableModel, dataIndex, cb, during) {
  animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during);
}


/**
 * Init graphic element properties with or without animation according to the
 * configuration in series.
 *
 * Caution: this method will stop previous animation.
 * So do not use this method to one element twice before
 * animation starts, unless you know what you are doing.
 */

function initProps(el, props, animatableModel, dataIndex, cb, during) {
  animateOrSetProps('init', el, props, animatableModel, dataIndex, cb, during);
}
/**
 * Remove graphic element
 */

function removeElement(el, props, animatableModel, dataIndex, cb, during) {
  // Don't do remove animation twice.
  if (isElementRemoved(el)) {
    return;
  }

  animateOrSetProps('remove', el, props, animatableModel, dataIndex, cb, during);
}

function fadeOutDisplayable(el, animatableModel, dataIndex, done) {
  el.removeTextContent();
  el.removeTextGuideLine();
  removeElement(el, {
    style: {
      opacity: 0
    }
  }, animatableModel, dataIndex, done);
}

function removeElementWithFadeOut(el, animatableModel, dataIndex) {
  function doRemove() {
    el.parent && el.parent.remove(el);
  } // Hide label and labelLine first
  // TODO Also use fade out animation?


  if (!el.isGroup) {
    fadeOutDisplayable(el, animatableModel, dataIndex, doRemove);
  } else {
    el.traverse(function (disp) {
      if (!disp.isGroup) {
        // Can invoke doRemove multiple times.
        fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove);
      }
    });
  }
}
/**
 * If element is removed.
 * It can determine if element is having remove animation.
 */

function isElementRemoved(el) {
  if (!el.__zr) {
    return true;
  }

  for (var i = 0; i < el.animators.length; i++) {
    var animator = el.animators[i];

    if (animator.scope === 'remove') {
      return true;
    }
  }

  return false;
}
/**
 * Get transform matrix of target (param target),
 * in coordinate of its ancestor (param ancestor)
 *
 * @param target
 * @param [ancestor]
 */

function getTransform(target, ancestor) {
  var mat = identity([]);

  while (target && target !== ancestor) {
    mul(mat, target.getLocalTransform(), mat);
    target = target.parent;
  }

  return mat;
}
/**
 * Apply transform to an vertex.
 * @param target [x, y]
 * @param transform Can be:
 *      + Transform matrix: like [1, 0, 0, 1, 0, 0]
 *      + {position, rotation, scale}, the same as `zrender/Transformable`.
 * @param invert Whether use invert matrix.
 * @return [x, y]
 */

function graphic_applyTransform(target, transform, invert) {
  if (transform && !isArrayLike(transform)) {
    transform = core_Transformable.getLocalTransform(transform);
  }

  if (invert) {
    transform = matrix_invert([], transform);
  }

  return applyTransform([], target, transform);
}
/**
 * @param direction 'left' 'right' 'top' 'bottom'
 * @param transform Transform matrix: like [1, 0, 0, 1, 0, 0]
 * @param invert Whether use invert matrix.
 * @return Transformed direction. 'left' 'right' 'top' 'bottom'
 */

function transformDirection(direction, transform, invert) {
  // Pick a base, ensure that transform result will not be (0, 0).
  var hBase = transform[4] === 0 || transform[5] === 0 || transform[0] === 0 ? 1 : Math.abs(2 * transform[4] / transform[0]);
  var vBase = transform[4] === 0 || transform[5] === 0 || transform[2] === 0 ? 1 : Math.abs(2 * transform[4] / transform[2]);
  var vertex = [direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0];
  vertex = graphic_applyTransform(vertex, transform, invert);
  return Math.abs(vertex[0]) > Math.abs(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top';
}

function isNotGroup(el) {
  return !el.isGroup;
}

function isPath(el) {
  return el.shape != null;
}
/**
 * Apply group transition animation from g1 to g2.
 * If no animatableModel, no animation.
 */


function groupTransition(g1, g2, animatableModel) {
  if (!g1 || !g2) {
    return;
  }

  function getElMap(g) {
    var elMap = {};
    g.traverse(function (el) {
      if (isNotGroup(el) && el.anid) {
        elMap[el.anid] = el;
      }
    });
    return elMap;
  }

  function getAnimatableProps(el) {
    var obj = {
      x: el.x,
      y: el.y,
      rotation: el.rotation
    };

    if (isPath(el)) {
      obj.shape = util_extend({}, el.shape);
    }

    return obj;
  }

  var elMap1 = getElMap(g1);
  g2.traverse(function (el) {
    if (isNotGroup(el) && el.anid) {
      var oldEl = elMap1[el.anid];

      if (oldEl) {
        var newProp = getAnimatableProps(el);
        el.attr(getAnimatableProps(oldEl));
        updateProps(el, newProp, animatableModel, getECData(el).dataIndex);
      }
    }
  });
}
function clipPointsByRect(points, rect) {
  // FIXME: this way migth be incorrect when grpahic clipped by a corner.
  // and when element have border.
  return map(points, function (point) {
    var x = point[0];
    x = graphic_mathMax(x, rect.x);
    x = graphic_mathMin(x, rect.x + rect.width);
    var y = point[1];
    y = graphic_mathMax(y, rect.y);
    y = graphic_mathMin(y, rect.y + rect.height);
    return [x, y];
  });
}
/**
 * Return a new clipped rect. If rect size are negative, return undefined.
 */

function clipRectByRect(targetRect, rect) {
  var x = graphic_mathMax(targetRect.x, rect.x);
  var x2 = graphic_mathMin(targetRect.x + targetRect.width, rect.x + rect.width);
  var y = graphic_mathMax(targetRect.y, rect.y);
  var y2 = graphic_mathMin(targetRect.y + targetRect.height, rect.y + rect.height); // If the total rect is cliped, nothing, including the border,
  // should be painted. So return undefined.

  if (x2 >= x && y2 >= y) {
    return {
      x: x,
      y: y,
      width: x2 - x,
      height: y2 - y
    };
  }
}
function createIcon(iconStr, // Support 'image://' or 'path://' or direct svg path.
opt, rect) {
  var innerOpts = util_extend({
    rectHover: true
  }, opt);
  var style = innerOpts.style = {
    strokeNoScale: true
  };
  rect = rect || {
    x: -1,
    y: -1,
    width: 2,
    height: 2
  };

  if (iconStr) {
    return iconStr.indexOf('image://') === 0 ? (style.image = iconStr.slice(8), util_defaults(style, rect), new graphic_Image(innerOpts)) : makePath(iconStr.replace('path://', ''), innerOpts, rect, 'center');
  }
}
/**
 * Return `true` if the given line (line `a`) and the given polygon
 * are intersect.
 * Note that we do not count colinear as intersect here because no
 * requirement for that. We could do that if required in future.
 */

function linePolygonIntersect(a1x, a1y, a2x, a2y, points) {
  for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) {
    var p = points[i];

    if (lineLineIntersect(a1x, a1y, a2x, a2y, p[0], p[1], p2[0], p2[1])) {
      return true;
    }

    p2 = p;
  }
}
/**
 * Return `true` if the given two lines (line `a` and line `b`)
 * are intersect.
 * Note that we do not count colinear as intersect here because no
 * requirement for that. We could do that if required in future.
 */

function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {
  // let `vec_m` to be `vec_a2 - vec_a1` and `vec_n` to be `vec_b2 - vec_b1`.
  var mx = a2x - a1x;
  var my = a2y - a1y;
  var nx = b2x - b1x;
  var ny = b2y - b1y; // `vec_m` and `vec_n` are parallel iff
  //     exising `k` such that `vec_m = k · vec_n`, equivalent to `vec_m X vec_n = 0`.

  var nmCrossProduct = crossProduct2d(nx, ny, mx, my);

  if (nearZero(nmCrossProduct)) {
    return false;
  } // `vec_m` and `vec_n` are intersect iff
  //     existing `p` and `q` in [0, 1] such that `vec_a1 + p * vec_m = vec_b1 + q * vec_n`,
  //     such that `q = ((vec_a1 - vec_b1) X vec_m) / (vec_n X vec_m)`
  //           and `p = ((vec_a1 - vec_b1) X vec_n) / (vec_n X vec_m)`.


  var b1a1x = a1x - b1x;
  var b1a1y = a1y - b1y;
  var q = crossProduct2d(b1a1x, b1a1y, mx, my) / nmCrossProduct;

  if (q < 0 || q > 1) {
    return false;
  }

  var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct;

  if (p < 0 || p > 1) {
    return false;
  }

  return true;
}
/**
 * Cross product of 2-dimension vector.
 */

function crossProduct2d(x1, y1, x2, y2) {
  return x1 * y2 - x2 * y1;
}

function nearZero(val) {
  return val <= 1e-6 && val >= -1e-6;
}

function setTooltipConfig(opt) {
  var itemTooltipOption = opt.itemTooltipOption;
  var componentModel = opt.componentModel;
  var itemName = opt.itemName;
  var itemTooltipOptionObj = isString(itemTooltipOption) ? {
    formatter: itemTooltipOption
  } : itemTooltipOption;
  var mainType = componentModel.mainType;
  var componentIndex = componentModel.componentIndex;
  var formatterParams = {
    componentType: mainType,
    name: itemName,
    $vars: ['name']
  };
  formatterParams[mainType + 'Index'] = componentIndex;
  var formatterParamsExtra = opt.formatterParamsExtra;

  if (formatterParamsExtra) {
    each(keys(formatterParamsExtra), function (key) {
      if (!hasOwn(formatterParams, key)) {
        formatterParams[key] = formatterParamsExtra[key];
        formatterParams.$vars.push(key);
      }
    });
  }

  var ecData = getECData(opt.el);
  ecData.componentMainType = mainType;
  ecData.componentIndex = componentIndex;
  ecData.tooltipConfig = {
    name: itemName,
    option: util_defaults({
      content: itemName,
      formatterParams: formatterParams
    }, itemTooltipOptionObj)
  };
} // Register built-in shapes. These shapes might be overwirtten
// by users, although we do not recommend that.

registerShape('circle', shape_Circle);
registerShape('ellipse', shape_Ellipse);
registerShape('sector', shape_Sector);
registerShape('ring', shape_Ring);
registerShape('polygon', shape_Polygon);
registerShape('polyline', shape_Polyline);
registerShape('rect', shape_Rect);
registerShape('line', shape_Line);
registerShape('bezierCurve', shape_BezierCurve);
registerShape('arc', shape_Arc);

;// CONCATENATED MODULE: ./node_modules/echarts/lib/label/labelStyle.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/






var EMPTY_OBJ = {};
function setLabelText(label, labelTexts) {
  for (var i = 0; i < SPECIAL_STATES.length; i++) {
    var stateName = SPECIAL_STATES[i];
    var text = labelTexts[stateName];
    var state = label.ensureState(stateName);
    state.style = state.style || {};
    state.style.text = text;
  }

  var oldStates = label.currentStates.slice();
  label.clearStates(true);
  label.setStyle({
    text: labelTexts.normal
  });
  label.useStates(oldStates, true);
}

function getLabelText(opt, stateModels, interpolatedValue) {
  var labelFetcher = opt.labelFetcher;
  var labelDataIndex = opt.labelDataIndex;
  var labelDimIndex = opt.labelDimIndex;
  var normalModel = stateModels.normal;
  var baseText;

  if (labelFetcher) {
    baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? {
      interpolatedValue: interpolatedValue
    } : null);
  }

  if (baseText == null) {
    baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText;
  }

  var statesText = {
    normal: baseText
  };

  for (var i = 0; i < SPECIAL_STATES.length; i++) {
    var stateName = SPECIAL_STATES[i];
    var stateModel = stateModels[stateName];
    statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText);
  }

  return statesText;
}

function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position?
) {
  opt = opt || EMPTY_OBJ;
  var isSetOnText = targetEl instanceof Text;
  var needsCreateText = false;

  for (var i = 0; i < DISPLAY_STATES.length; i++) {
    var stateModel = labelStatesModels[DISPLAY_STATES[i]];

    if (stateModel && stateModel.getShallow('show')) {
      needsCreateText = true;
      break;
    }
  }

  var textContent = isSetOnText ? targetEl : targetEl.getTextContent();

  if (needsCreateText) {
    if (!isSetOnText) {
      // Reuse the previous
      if (!textContent) {
        textContent = new Text();
        targetEl.setTextContent(textContent);
      } // Use same state proxy


      if (targetEl.stateProxy) {
        textContent.stateProxy = targetEl.stateProxy;
      }
    }

    var labelStatesTexts = getLabelText(opt, labelStatesModels);
    var normalModel = labelStatesModels.normal;
    var showNormal = !!normalModel.getShallow('show');
    var normalStyle = createTextStyle(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText);
    normalStyle.text = labelStatesTexts.normal;

    if (!isSetOnText) {
      // Always create new
      targetEl.setTextConfig(createTextConfig(normalModel, opt, false));
    }

    for (var i = 0; i < SPECIAL_STATES.length; i++) {
      var stateName = SPECIAL_STATES[i];
      var stateModel = labelStatesModels[stateName];

      if (stateModel) {
        var stateObj = textContent.ensureState(stateName);
        var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal);

        if (stateShow !== showNormal) {
          stateObj.ignore = !stateShow;
        }

        stateObj.style = createTextStyle(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText);
        stateObj.style.text = labelStatesTexts[stateName];

        if (!isSetOnText) {
          var targetElEmphasisState = targetEl.ensureState(stateName);
          targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true);
        }
      }
    } // PENDING: if there is many requirements that emphasis position
    // need to be different from normal position, we might consider
    // auto slient is those cases.


    textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y

    if (textContent.style.x != null) {
      normalStyle.x = textContent.style.x;
    }

    if (textContent.style.y != null) {
      normalStyle.y = textContent.style.y;
    }

    textContent.ignore = !showNormal; // Always create new style.

    textContent.useStyle(normalStyle);
    textContent.dirty();

    if (opt.enableTextSetter) {
      labelInner(textContent).setLabelText = function (interpolatedValue) {
        var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue);
        setLabelText(textContent, labelStatesTexts);
      };
    }
  } else if (textContent) {
    // Not display rich text.
    textContent.ignore = true;
  }

  targetEl.dirty();
}


function getLabelStatesModels(itemModel, labelName) {
  labelName = labelName || 'label';
  var statesModels = {
    normal: itemModel.getModel(labelName)
  };

  for (var i = 0; i < SPECIAL_STATES.length; i++) {
    var stateName = SPECIAL_STATES[i];
    statesModels[stateName] = itemModel.getModel([stateName, labelName]);
  }

  return statesModels;
}
/**
 * Set basic textStyle properties.
 */

function createTextStyle(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model.
opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender.
) {
  var textStyle = {};
  setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
  specifiedTextStyle && util_extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);

  return textStyle;
}
function createTextConfig(textStyleModel, opt, isNotNormal) {
  opt = opt || {};
  var textConfig = {};
  var labelPosition;
  var labelRotate = textStyleModel.getShallow('rotate');
  var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5);
  var labelOffset = textStyleModel.getShallow('offset');
  labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used
  // in bar series, and magric type should be considered.

  labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');

  if (labelPosition != null) {
    textConfig.position = labelPosition;
  }

  if (labelOffset != null) {
    textConfig.offset = labelOffset;
  }

  if (labelRotate != null) {
    labelRotate *= Math.PI / 180;
    textConfig.rotation = labelRotate;
  }

  if (labelDistance != null) {
    textConfig.distance = labelDistance;
  } // fill and auto is determined by the color of path fill if it's not specified by developers.


  textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto';
  return textConfig;
}
/**
 * The uniform entry of set text style, that is, retrieve style definitions
 * from `model` and set to `textStyle` object.
 *
 * Never in merge mode, but in overwrite mode, that is, all of the text style
 * properties will be set. (Consider the states of normal and emphasis and
 * default value can be adopted, merge would make the logic too complicated
 * to manage.)
 */

function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) {
  // Consider there will be abnormal when merge hover style to normal style if given default value.
  opt = opt || EMPTY_OBJ;
  var ecModel = textStyleModel.ecModel;
  var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case:
  // {
  //     data: [{
  //         value: 12,
  //         label: {
  //             rich: {
  //                 // no 'a' here but using parent 'a'.
  //             }
  //         }
  //     }],
  //     rich: {
  //         a: { ... }
  //     }
  // }

  var richItemNames = getRichItemNames(textStyleModel);
  var richResult;

  if (richItemNames) {
    richResult = {};

    for (var name_1 in richItemNames) {
      if (richItemNames.hasOwnProperty(name_1)) {
        // Cascade is supported in rich.
        var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`.
        // FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`,
        // the default color `'blue'` will not be adopted if no color declared in `rich`.
        // That might confuses users. So probably we should put `textStyleModel` as the
        // root ancestor of the `richTextStyle`. But that would be a break change.

        setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached, false, true);
      }
    }
  }

  if (richResult) {
    textStyle.rich = richResult;
  }

  var overflow = textStyleModel.get('overflow');

  if (overflow) {
    textStyle.overflow = overflow;
  }

  var margin = textStyleModel.get('minMargin');

  if (margin != null) {
    textStyle.margin = margin;
  }

  setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true, false);
} // Consider case:
// {
//     data: [{
//         value: 12,
//         label: {
//             rich: {
//                 // no 'a' here but using parent 'a'.
//             }
//         }
//     }],
//     rich: {
//         a: { ... }
//     }
// }
// TODO TextStyleModel


function getRichItemNames(textStyleModel) {
  // Use object to remove duplicated names.
  var richItemNameMap;

  while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
    var rich = (textStyleModel.option || EMPTY_OBJ).rich;

    if (rich) {
      richItemNameMap = richItemNameMap || {};
      var richKeys = keys(rich);

      for (var i = 0; i < richKeys.length; i++) {
        var richKey = richKeys[i];
        richItemNameMap[richKey] = 1;
      }
    }

    textStyleModel = textStyleModel.parentModel;
  }

  return richItemNameMap;
}

var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'];
var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign'];
var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];

function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, isBlock, inRich) {
  // In merge mode, default value should not be given.
  globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
  var inheritColor = opt && opt.inheritColor;
  var fillColor = textStyleModel.getShallow('color');
  var strokeColor = textStyleModel.getShallow('textBorderColor');
  var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity);

  if (fillColor === 'inherit' || fillColor === 'auto') {
    if (true) {
      if (fillColor === 'auto') {
        deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
      }
    }

    if (inheritColor) {
      fillColor = inheritColor;
    } else {
      fillColor = null;
    }
  }

  if (strokeColor === 'inherit' || strokeColor === 'auto') {
    if (true) {
      if (strokeColor === 'auto') {
        deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
      }
    }

    if (inheritColor) {
      strokeColor = inheritColor;
    } else {
      strokeColor = null;
    }
  }

  if (!isAttached) {
    // Only use default global textStyle.color if text is individual.
    // Otherwise it will use the strategy of attached text color because text may be on a path.
    fillColor = fillColor || globalTextStyle.color;
    strokeColor = strokeColor || globalTextStyle.textBorderColor;
  }

  if (fillColor != null) {
    textStyle.fill = fillColor;
  }

  if (strokeColor != null) {
    textStyle.stroke = strokeColor;
  }

  var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth);

  if (textBorderWidth != null) {
    textStyle.lineWidth = textBorderWidth;
  }

  var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType);

  if (textBorderType != null) {
    textStyle.lineDash = textBorderType;
  }

  var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset);

  if (textBorderDashOffset != null) {
    textStyle.lineDashOffset = textBorderDashOffset;
  }

  if (!isNotNormal && opacity == null && !inRich) {
    opacity = opt && opt.defaultOpacity;
  }

  if (opacity != null) {
    textStyle.opacity = opacity;
  } // TODO


  if (!isNotNormal && !isAttached) {
    // Set default finally.
    if (textStyle.fill == null && opt.inheritColor) {
      textStyle.fill = opt.inheritColor;
    }
  } // Do not use `getFont` here, because merge should be supported, where
  // part of these properties may be changed in emphasis style, and the
  // others should remain their original value got from normal style.


  for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
    var key = TEXT_PROPS_WITH_GLOBAL[i];
    var val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);

    if (val != null) {
      textStyle[key] = val;
    }
  }

  for (var i = 0; i < TEXT_PROPS_SELF.length; i++) {
    var key = TEXT_PROPS_SELF[i];
    var val = textStyleModel.getShallow(key);

    if (val != null) {
      textStyle[key] = val;
    }
  }

  if (textStyle.verticalAlign == null) {
    var baseline = textStyleModel.getShallow('baseline');

    if (baseline != null) {
      textStyle.verticalAlign = baseline;
    }
  }

  if (!isBlock || !opt.disableBox) {
    for (var i = 0; i < TEXT_PROPS_BOX.length; i++) {
      var key = TEXT_PROPS_BOX[i];
      var val = textStyleModel.getShallow(key);

      if (val != null) {
        textStyle[key] = val;
      }
    }

    var borderType = textStyleModel.getShallow('borderType');

    if (borderType != null) {
      textStyle.borderDash = borderType;
    }

    if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) {
      if (true) {
        if (textStyle.backgroundColor === 'auto') {
          deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\'');
        }
      }

      textStyle.backgroundColor = inheritColor;
    }

    if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) {
      if (true) {
        if (textStyle.borderColor === 'auto') {
          deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\'');
        }
      }

      textStyle.borderColor = inheritColor;
    }
  }
}

function getFont(opt, ecModel) {
  var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
  return trim([// FIXME in node-canvas fontWeight is before fontStyle
  opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' '));
}
var labelInner = makeInner();
function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) {
  if (!label) {
    return;
  }

  var obj = labelInner(label);
  obj.prevValue = obj.value;
  obj.value = value;
  var normalLabelModel = labelStatesModels.normal;
  obj.valueAnimation = normalLabelModel.get('valueAnimation');

  if (obj.valueAnimation) {
    obj.precision = normalLabelModel.get('precision');
    obj.defaultInterpolatedText = getDefaultText;
    obj.statesModels = labelStatesModels;
  }
}
function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) {
  var labelInnerStore = labelInner(textEl);

  if (!labelInnerStore.valueAnimation) {
    return;
  }

  var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`,
  // Otherwise it will jump to the `obj.value` when this new animation started.

  var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue);
  var targetValue = labelInnerStore.value;

  function during(percent) {
    var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent);
    labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated;
    var labelText = getLabelText({
      labelDataIndex: dataIndex,
      labelFetcher: labelFetcher,
      defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + ''
    }, labelInnerStore.statesModels, interpolated);
    setLabelText(textEl, labelText);
  }

  (currValue == null ? initProps : updateProps)(textEl, {}, animatableModel, dataIndex, null, during);
}
;// CONCATENATED MODULE: ./src/util/OrbitControl.js
/**
 * Provide orbit control for 3D objects
 *
 * @module echarts-gl/util/OrbitControl
 * @author Yi Shen(http://github.com/pissang)
 */

// TODO Remove magic numbers on sensitivity





var firstNotNull = util_retrieve.firstNotNull;


var MOUSE_BUTTON_KEY_MAP = {
    left: 0,
    middle: 1,
    right: 2
};

function convertToArray(val) {
    if (!(val instanceof Array)) {
        val = [val, val];
    }
    return val;
}

/**
 * @alias module:echarts-x/util/OrbitControl
 */
var OrbitControl = core_Base.extend(function () {

    return {
        /**
         * @type {module:zrender~ZRender}
         */
        zr: null,

        /**
         * @type {module:echarts-gl/core/ViewGL}
         */
        viewGL: null,

        /**
         * @type {clay.math.Vector3}
         */
        _center: new math_Vector3(),

        /**
         * Minimum distance to the center
         * Only available when camera is perspective.
         * @type {number}
         * @default 0.5
         */
        minDistance: 0.5,

        /**
         * Maximum distance to the center
         * Only available when camera is perspective.
         * @type {number}
         * @default 2
         */
        maxDistance: 1.5,

        /**
         * Only available when camera is orthographic
         */
        maxOrthographicSize: 300,

        /**
         * Only available when camera is orthographic
         */
        minOrthographicSize: 30,

        /**
         * Minimum alpha rotation
         */
        minAlpha: -90,

        /**
         * Maximum alpha rotation
         */
        maxAlpha: 90,

        /**
         * Minimum beta rotation
         */
        minBeta: -Infinity,
        /**
         * Maximum beta rotation
         */
        maxBeta: Infinity,

        /**
         * Start auto rotating after still for the given time
         */
        autoRotateAfterStill: 0,

        /**
         * Direction of autoRotate. cw or ccw when looking top down.
         */
        autoRotateDirection: 'cw',

        /**
         * Degree per second
         */
        autoRotateSpeed: 60,

        /**
         * @param {number}
         */
        damping: 0.8,

        /**
         * @param {number}
         */
        rotateSensitivity: 1,

        /**
         * @param {number}
         */
        zoomSensitivity: 1,

        /**
         * @param {number}
         */
        panSensitivity: 1,

        panMouseButton: 'middle',
        rotateMouseButton: 'left',

        /**
         * Pan or rotate
         * @private
         * @type {String}
         */
        _mode: 'rotate',

        /**
         * @private
         * @type {clay.Camera}
         */
        _camera: null,

        _needsUpdate: false,

        _rotating: false,

        // Rotation around yAxis in radian
        _phi: 0,
        // Rotation around xAxis in radian
        _theta: 0,

        _mouseX: 0,
        _mouseY: 0,

        _rotateVelocity: new math_Vector2(),

        _panVelocity: new math_Vector2(),

        _distance: 500,

        _zoomSpeed: 0,

        _stillTimeout: 0,

        _animators: []
    };
}, function () {
    // Each OrbitControl has it's own handler
    ['_mouseDownHandler', '_mouseWheelHandler', '_mouseMoveHandler', '_mouseUpHandler',
    '_pinchHandler', '_contextMenuHandler', '_update'].forEach(function (hdlName) {
        this[hdlName] = this[hdlName].bind(this);
    }, this);
}, {
    /**
     * Initialize.
     * Mouse event binding
     */
    init: function () {
        var zr = this.zr;

        if (zr) {
            zr.on('mousedown', this._mouseDownHandler);
            zr.on('globalout', this._mouseUpHandler);
            zr.on('mousewheel', this._mouseWheelHandler);
            zr.on('pinch', this._pinchHandler);

            zr.animation.on('frame', this._update);

            zr.dom.addEventListener('contextmenu', this._contextMenuHandler);
        }
    },

    /**
     * Dispose.
     * Mouse event unbinding
     */
    dispose: function () {
        var zr = this.zr;

        if (zr) {
            zr.off('mousedown', this._mouseDownHandler);
            zr.off('mousemove', this._mouseMoveHandler);
            zr.off('mouseup', this._mouseUpHandler);
            zr.off('mousewheel', this._mouseWheelHandler);
            zr.off('pinch', this._pinchHandler);
            zr.off('globalout', this._mouseUpHandler);
            zr.dom.removeEventListener('contextmenu', this._contextMenuHandler);

            zr.animation.off('frame', this._update);
        }
        this.stopAllAnimation();
    },

    /**
     * Get distance
     * @return {number}
     */
    getDistance: function () {
        return this._distance;
    },

    /**
     * Set distance
     * @param {number} distance
     */
    setDistance: function (distance) {
        this._distance = distance;
        this._needsUpdate = true;
    },

    /**
     * Get size of orthographic viewing volume
     * @return {number}
     */
    getOrthographicSize: function () {
        return this._orthoSize;
    },

    /**
     * Set size of orthographic viewing volume
     * @param {number} size
     */
    setOrthographicSize: function (size) {
        this._orthoSize = size;
        this._needsUpdate = true;
    },

    /**
     * Get alpha rotation
     * Alpha angle for top-down rotation. Positive to rotate to top.
     *
     * Which means camera rotation around x axis.
     */
    getAlpha: function () {
        return this._theta / Math.PI * 180;
    },

    /**
     * Get beta rotation
     * Beta angle for left-right rotation. Positive to rotate to right.
     *
     * Which means camera rotation around y axis.
     */
    getBeta: function () {
        return -this._phi / Math.PI * 180;
    },

    /**
     * Get control center
     * @return {Array.<number>}
     */
    getCenter: function () {
        return this._center.toArray();
    },

    /**
     * Set alpha rotation angle
     * @param {number} alpha
     */
    setAlpha: function (alpha) {
        alpha = Math.max(Math.min(this.maxAlpha, alpha), this.minAlpha);

        this._theta = alpha / 180 * Math.PI;
        this._needsUpdate = true;
    },

    /**
     * Set beta rotation angle
     * @param {number} beta
     */
    setBeta: function (beta) {
        beta = Math.max(Math.min(this.maxBeta, beta), this.minBeta);

        this._phi = -beta / 180 * Math.PI;
        this._needsUpdate = true;
    },

    /**
     * Set control center
     * @param {Array.<number>} center
     */
    setCenter: function (centerArr) {
        this._center.setArray(centerArr);
    },

    /**
     * @param {module:echarts-gl/core/ViewGL} viewGL
     */
    setViewGL: function (viewGL) {
        this.viewGL = viewGL;
    },

    /**
     * @return {clay.Camera}
     */
    getCamera: function () {
        return this.viewGL.camera;
    },

    setFromViewControlModel: function (viewControlModel, extraOpts) {
        extraOpts = extraOpts || {};
        var baseDistance = extraOpts.baseDistance || 0;
        var baseOrthoSize = extraOpts.baseOrthoSize || 1;

        var projection = viewControlModel.get('projection');
        if (projection !== 'perspective' && projection !== 'orthographic' && projection !== 'isometric') {
            if (true) {
                console.error('Unkown projection type %s, use perspective projection instead.', projection);
            }
            projection = 'perspective';
        }
        this._projection = projection;
        this.viewGL.setProjection(projection);

        var targetDistance = viewControlModel.get('distance') + baseDistance;
        var targetOrthographicSize = viewControlModel.get('orthographicSize') + baseOrthoSize;

        [
            ['damping', 0.8],
            ['autoRotate', false],
            ['autoRotateAfterStill', 3],
            ['autoRotateDirection', 'cw'],
            ['autoRotateSpeed', 10],
            ['minDistance', 30],
            ['maxDistance', 400],
            ['minOrthographicSize', 30],
            ['maxOrthographicSize', 300],
            ['minAlpha', -90],
            ['maxAlpha', 90],
            ['minBeta', -Infinity],
            ['maxBeta', Infinity],
            ['rotateSensitivity', 1],
            ['zoomSensitivity', 1],
            ['panSensitivity', 1],
            ['panMouseButton', 'left'],
            ['rotateMouseButton', 'middle'],
        ].forEach(function (prop) {
            this[prop[0]] = firstNotNull(viewControlModel.get(prop[0]), prop[1]);
        }, this);

        this.minDistance += baseDistance;
        this.maxDistance += baseDistance;
        this.minOrthographicSize += baseOrthoSize,
        this.maxOrthographicSize += baseOrthoSize;

        var ecModel = viewControlModel.ecModel;

        var animationOpts = {};
        ['animation', 'animationDurationUpdate', 'animationEasingUpdate'].forEach(function (key) {
            animationOpts[key] = firstNotNull(
                viewControlModel.get(key), ecModel && ecModel.get(key)
            );
        });

        var alpha = firstNotNull(extraOpts.alpha, viewControlModel.get('alpha')) || 0;
        var beta = firstNotNull(extraOpts.beta, viewControlModel.get('beta')) || 0;
        var center = firstNotNull(extraOpts.center, viewControlModel.get('center')) || [0, 0, 0];
        if (animationOpts.animation && animationOpts.animationDurationUpdate > 0 && this._notFirst) {
            this.animateTo({
                alpha: alpha,
                beta: beta,
                center: center,
                distance: targetDistance,
                orthographicSize: targetOrthographicSize,
                easing: animationOpts.animationEasingUpdate,
                duration: animationOpts.animationDurationUpdate
            });
        }
        else {
            this.setDistance(targetDistance);
            this.setAlpha(alpha);
            this.setBeta(beta);
            this.setCenter(center);
            this.setOrthographicSize(targetOrthographicSize);
        }

        this._notFirst = true;

        this._validateProperties();
    },

    _validateProperties: function () {
        if (true) {
            if (MOUSE_BUTTON_KEY_MAP[this.panMouseButton] == null) {
                console.error('Unkown panMouseButton %s. It should be left|middle|right', this.panMouseButton);
            }
            if (MOUSE_BUTTON_KEY_MAP[this.rotateMouseButton] == null) {
                console.error('Unkown rotateMouseButton %s. It should be left|middle|right', this.rotateMouseButton);
            }
            if (this.autoRotateDirection !== 'cw' && this.autoRotateDirection !== 'ccw') {
                console.error('Unkown autoRotateDirection %s. It should be cw|ccw', this.autoRotateDirection);
            }
        }
    },

    /**
     * @param {Object} opts
     * @param {number} opts.distance
     * @param {number} opts.alpha
     * @param {number} opts.beta
     * @param {number} opts.orthographicSize
     * @param {number} [opts.duration=1000]
     * @param {number} [opts.easing='linear']
     */
    animateTo: function (opts) {
        var zr = this.zr;
        var self = this;

        var obj = {};
        var target = {};

        if (opts.distance != null) {
            obj.distance = this.getDistance();
            target.distance = opts.distance;
        }
        if (opts.orthographicSize != null) {
            obj.orthographicSize = this.getOrthographicSize();
            target.orthographicSize = opts.orthographicSize;
        }
        if (opts.alpha != null) {
            obj.alpha = this.getAlpha();
            target.alpha = opts.alpha;
        }
        if (opts.beta != null) {
            obj.beta = this.getBeta();
            target.beta = opts.beta;
        }
        if (opts.center != null) {
            obj.center = this.getCenter();
            target.center = opts.center;
        }

        return this._addAnimator(
            zr.animation.animate(obj)
                .when(opts.duration || 1000, target)
                .during(function () {
                    if (obj.alpha != null) {
                        self.setAlpha(obj.alpha);
                    }
                    if (obj.beta != null) {
                        self.setBeta(obj.beta);
                    }
                    if (obj.distance != null) {
                        self.setDistance(obj.distance);
                    }
                    if (obj.center != null) {
                        self.setCenter(obj.center);
                    }
                    if (obj.orthographicSize != null) {
                        self.setOrthographicSize(obj.orthographicSize);
                    }
                    self._needsUpdate = true;
                })
        ).start(opts.easing || 'linear');
    },

    /**
     * Stop all animation
     */
    stopAllAnimation: function () {
        for (var i = 0; i < this._animators.length; i++) {
            this._animators[i].stop();
        }
        this._animators.length = 0;
    },

    update: function () {
        this._needsUpdate = true;
        this._update(20);
    },

    _isAnimating: function () {
        return this._animators.length > 0;
    },
    /**
     * Call update each frame
     * @param  {number} deltaTime Frame time
     */
    _update: function (deltaTime) {

        if (this._rotating) {
            var radian = (this.autoRotateDirection === 'cw' ? 1 : -1)
                 * this.autoRotateSpeed / 180 * Math.PI;
            this._phi -= radian * deltaTime / 1000;
            this._needsUpdate = true;
        }
        else if (this._rotateVelocity.len() > 0) {
            this._needsUpdate = true;
        }

        if (Math.abs(this._zoomSpeed) > 0.1 || this._panVelocity.len() > 0) {
            this._needsUpdate = true;
        }

        if (!this._needsUpdate) {
            return;
        }

        deltaTime = Math.min(deltaTime, 50);

        this._updateDistanceOrSize(deltaTime);

        this._updatePan(deltaTime);

        this._updateRotate(deltaTime);

        this._updateTransform();

        this.getCamera().update();

        this.zr && this.zr.refresh();

        this.trigger('update');

        this._needsUpdate = false;
    },

    _updateRotate: function (deltaTime) {
        var velocity = this._rotateVelocity;
        this._phi = velocity.y * deltaTime / 20 + this._phi;
        this._theta = velocity.x * deltaTime / 20 + this._theta;

        this.setAlpha(this.getAlpha());
        this.setBeta(this.getBeta());

        this._vectorDamping(velocity, Math.pow(this.damping, deltaTime / 16));
    },

    _updateDistanceOrSize: function (deltaTime) {
        if (this._projection === 'perspective') {
            this._setDistance(this._distance + this._zoomSpeed * deltaTime / 20);
        }
        else {
            this._setOrthoSize(this._orthoSize + this._zoomSpeed * deltaTime / 20);
        }

        this._zoomSpeed *= Math.pow(this.damping, deltaTime / 16);
    },


    _setDistance: function (distance) {
        this._distance = Math.max(Math.min(distance, this.maxDistance), this.minDistance);
    },

    _setOrthoSize: function (size) {
        this._orthoSize = Math.max(Math.min(size, this.maxOrthographicSize), this.minOrthographicSize);
        var camera = this.getCamera();
        var cameraHeight = this._orthoSize;
        var cameraWidth = cameraHeight / this.viewGL.viewport.height * this.viewGL.viewport.width;
        camera.left = -cameraWidth / 2;
        camera.right = cameraWidth / 2;
        camera.top = cameraHeight / 2;
        camera.bottom = -cameraHeight / 2;
    },

    _updatePan: function (deltaTime) {

        var velocity = this._panVelocity;
        var len = this._distance;

        var target = this.getCamera();
        var yAxis = target.worldTransform.y;
        var xAxis = target.worldTransform.x;

        // PENDING
        this._center
            .scaleAndAdd(xAxis, -velocity.x * len / 200)
            .scaleAndAdd(yAxis, -velocity.y * len / 200);

        this._vectorDamping(velocity, 0);
    },

    _updateTransform: function () {
        var camera = this.getCamera();

        var dir = new math_Vector3();
        var theta = this._theta + Math.PI / 2;
        var phi = this._phi + Math.PI / 2;
        var r = Math.sin(theta);

        dir.x = r * Math.cos(phi);
        dir.y = -Math.cos(theta);
        dir.z = r * Math.sin(phi);

        camera.position.copy(this._center).scaleAndAdd(dir, this._distance);
        camera.rotation.identity()
            // First around y, then around x
            .rotateY(-this._phi)
            .rotateX(-this._theta);
    },

    _startCountingStill: function () {
        clearTimeout(this._stillTimeout);

        var time = this.autoRotateAfterStill;
        var self = this;
        if (!isNaN(time) && time > 0) {
            this._stillTimeout = setTimeout(function () {
                self._rotating = true;
            }, time * 1000);
        }
    },

    _vectorDamping: function (v, damping) {
        var speed = v.len();
        speed = speed * damping;
        if (speed < 1e-4) {
            speed = 0;
        }
        v.normalize().scale(speed);
    },

    _decomposeTransform: function () {
        if (!this.getCamera()) {
            return;
        }

        this.getCamera().updateWorldTransform();

        var forward = this.getCamera().worldTransform.z;
        var alpha = Math.asin(forward.y);
        var beta = Math.atan2(forward.x, forward.z);

        this._theta = alpha;
        this._phi = -beta;

        this.setBeta(this.getBeta());
        this.setAlpha(this.getAlpha());

        // Is perspective
        if (this.getCamera().aspect) {
            this._setDistance(this.getCamera().position.dist(this._center));
        }
        else {
            this._setOrthoSize(this.getCamera().top - this.getCamera().bottom);
        }
    },

    _mouseDownHandler: function (e) {
        if (e.target) {
            // If mouseon some zrender element.
            return;
        }
        if (this._isAnimating()) {
            return;
        }

        var x = e.offsetX;
        var y = e.offsetY;
        if (this.viewGL && !this.viewGL.containPoint(x, y)) {
            return;
        }

        this.zr.on('mousemove', this._mouseMoveHandler);
        this.zr.on('mouseup', this._mouseUpHandler);

        if (e.event.targetTouches) {
            if (e.event.targetTouches.length === 1) {
                this._mode = 'rotate';
            }
        }
        else {
            if (e.event.button === MOUSE_BUTTON_KEY_MAP[this.rotateMouseButton]) {
                this._mode = 'rotate';
            }
            else if (e.event.button === MOUSE_BUTTON_KEY_MAP[this.panMouseButton]) {
                this._mode = 'pan';
            }
            else {
                this._mode = '';
            }
        }

        // Reset rotate velocity
        this._rotateVelocity.set(0, 0);
        this._rotating = false;
        if (this.autoRotate) {
            this._startCountingStill();
        }

        this._mouseX = e.offsetX;
        this._mouseY = e.offsetY;
    },

    _mouseMoveHandler: function (e) {
        if (e.target && e.target.__isGLToZRProxy) {
            return;
        }

        if (this._isAnimating()) {
            return;
        }

        var panSensitivity = convertToArray(this.panSensitivity);
        var rotateSensitivity = convertToArray(this.rotateSensitivity);

        if (this._mode === 'rotate') {
            this._rotateVelocity.y = (e.offsetX - this._mouseX) / this.zr.getHeight() * 2 * rotateSensitivity[0];
            this._rotateVelocity.x = (e.offsetY - this._mouseY) / this.zr.getWidth() * 2 * rotateSensitivity[1];
        }
        else if (this._mode === 'pan') {
            this._panVelocity.x = (e.offsetX - this._mouseX) / this.zr.getWidth() * panSensitivity[0] * 400;
            this._panVelocity.y = (-e.offsetY + this._mouseY) / this.zr.getHeight() * panSensitivity[1] * 400;
        }


        this._mouseX = e.offsetX;
        this._mouseY = e.offsetY;

        e.event.preventDefault();
    },

    _mouseWheelHandler: function (e) {
        if (this._isAnimating()) {
            return;
        }
        var delta = e.event.wheelDelta // Webkit
                || -e.event.detail; // Firefox
        this._zoomHandler(e, delta);
    },

    _pinchHandler: function (e) {
        if (this._isAnimating()) {
            return;
        }
        this._zoomHandler(e, e.pinchScale > 1 ? 1 : -1);
        // Not rotate when pinch
        this._mode = '';
    },

    _zoomHandler: function (e, delta) {
        if (delta === 0) {
            return;
        }

        var x = e.offsetX;
        var y = e.offsetY;
        if (this.viewGL && !this.viewGL.containPoint(x, y)) {
            return;
        }

        var speed;
        if (this._projection === 'perspective') {
            speed = Math.max(Math.max(Math.min(
                this._distance - this.minDistance,
                this.maxDistance - this._distance
            )) / 20, 0.5);
        }
        else {
            speed = Math.max(Math.max(Math.min(
                this._orthoSize - this.minOrthographicSize,
                this.maxOrthographicSize - this._orthoSize
            )) / 20, 0.5);
        }
        this._zoomSpeed = (delta > 0 ? -1 : 1) * speed * this.zoomSensitivity;

        this._rotating = false;

        if (this.autoRotate && this._mode === 'rotate') {
            this._startCountingStill();
        }

        e.event.preventDefault();
    },

    _mouseUpHandler: function () {
        this.zr.off('mousemove', this._mouseMoveHandler);
        this.zr.off('mouseup', this._mouseUpHandler);
    },

    _isRightMouseButtonUsed: function () {
        return this.rotateMouseButton === 'right'
            || this.panMouseButton === 'right';
    },

    _contextMenuHandler: function (e) {
        if (this._isRightMouseButtonUsed()) {
            e.preventDefault();
        }
    },

    _addAnimator: function (animator) {
        var animators = this._animators;
        animators.push(animator);
        animator.done(function () {
            var idx = animators.indexOf(animator);
            if (idx >= 0) {
                animators.splice(idx, 1);
            }
        });
        return animator;
    }
});

/**
 * If auto rotate the target
 * @type {boolean}
 * @default false
 */
Object.defineProperty(OrbitControl.prototype, 'autoRotate', {
    get: function (val) {
        return this._autoRotate;
    },
    set: function (val) {
        this._autoRotate = val;
        this._rotating = val;
    }
});


/* harmony default export */ const util_OrbitControl = (OrbitControl);
;// CONCATENATED MODULE: ./src/util/geometry/dynamicConvertMixin.js
/* harmony default export */ const dynamicConvertMixin = ({
    convertToDynamicArray: function (clear) {
        if (clear) {
            this.resetOffset();
        }
        var attributes = this.attributes;
        for (var name in attributes) {
            if (clear || !attributes[name].value) {
                attributes[name].value = [];
            }
            else {
                attributes[name].value = Array.prototype.slice.call(attributes[name].value);
            }
        }
        if (clear || !this.indices) {
            this.indices = [];
        }
        else {
            this.indices = Array.prototype.slice.call(this.indices);
        }
    },

    convertToTypedArray: function () {
        var attributes = this.attributes;
        for (var name in attributes) {
            if (attributes[name].value && attributes[name].value.length > 0) {
                attributes[name].value = new Float32Array(attributes[name].value);
            }
            else {
                attributes[name].value = null;
            }
        }
        if (this.indices && this.indices.length > 0) {
            this.indices = this.vertexCount > 0xffff ? new Uint32Array(this.indices) : new Uint16Array(this.indices);
        }

        this.dirty();
    }
});
;// CONCATENATED MODULE: ./node_modules/claygl/src/glmatrix/index.js
/**
 * @fileoverview gl-matrix - High performance matrix and vector operations
 * @author Brandon Jones
 * @author Colin MacKenzie IV
 * @version 2.2.2
 */

/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this
    list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */










/* harmony default export */ const glmatrix = ({
    vec2: glmatrix_vec2,
    vec3: glmatrix_vec3,
    vec4: glmatrix_vec4,
    mat2: glmatrix_mat2,
    mat2d: glmatrix_mat2d,
    mat3: glmatrix_mat3,
    mat4: glmatrix_mat4,
    quat: glmatrix_quat
});

;// CONCATENATED MODULE: ./node_modules/claygl/src/dep/glmatrix.js
// DEPRECATED


/* harmony default export */ const dep_glmatrix = (glmatrix);

;// CONCATENATED MODULE: ./src/util/geometry/Lines3D.js
/**
 * Lines geometry
 * Use screen space projected lines lineWidth > MAX_LINE_WIDTH
 * https://mattdesl.svbtle.com/drawing-lines-is-hard
 * @module echarts-gl/util/geometry/LinesGeometry
 * @author Yi Shen(http://github.com/pissang)
 */





var Lines3D_vec3 = dep_glmatrix.vec3;

// var CURVE_RECURSION_LIMIT = 8;
// var CURVE_COLLINEAR_EPSILON = 40;

var sampleLinePoints = [[0, 0], [1, 1]];
/**
 * @constructor
 * @alias module:echarts-gl/util/geometry/LinesGeometry
 * @extends clay.Geometry
 */

var LinesGeometry = src_Geometry.extend(function () {
    return {

        segmentScale: 1,

        dynamic: true,
        /**
         * Need to use mesh to expand lines if lineWidth > MAX_LINE_WIDTH
         */
        useNativeLine: true,

        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 3, 'POSITION'),
            positionPrev: new src_Geometry.Attribute('positionPrev', 'float', 3),
            positionNext: new src_Geometry.Attribute('positionNext', 'float', 3),
            prevPositionPrev: new src_Geometry.Attribute('prevPositionPrev', 'float', 3),
            prevPosition: new src_Geometry.Attribute('prevPosition', 'float', 3),
            prevPositionNext: new src_Geometry.Attribute('prevPositionNext', 'float', 3),
            offset: new src_Geometry.Attribute('offset', 'float', 1),
            color: new src_Geometry.Attribute('color', 'float', 4, 'COLOR')
        }
    };
},
/** @lends module: echarts-gl/util/geometry/LinesGeometry.prototype */
{

    /**
     * Reset offset
     */
    resetOffset: function () {
        this._vertexOffset = 0;
        this._triangleOffset = 0;

        this._itemVertexOffsets = [];
    },

    /**
     * @param {number} nVertex
     */
    setVertexCount: function (nVertex) {
        var attributes = this.attributes;
        if (this.vertexCount !== nVertex) {
            attributes.position.init(nVertex);
            attributes.color.init(nVertex);

            if (!this.useNativeLine) {
                attributes.positionPrev.init(nVertex);
                attributes.positionNext.init(nVertex);
                attributes.offset.init(nVertex);
            }

            if (nVertex > 0xffff) {
                if (this.indices instanceof Uint16Array) {
                    this.indices = new Uint32Array(this.indices);
                }
            }
            else {
                if (this.indices instanceof Uint32Array) {
                    this.indices = new Uint16Array(this.indices);
                }
            }
        }
    },

    /**
     * @param {number} nTriangle
     */
    setTriangleCount: function (nTriangle) {
        if (this.triangleCount !== nTriangle) {
            if (nTriangle === 0) {
                this.indices = null;
            }
            else {
                this.indices = this.vertexCount > 0xffff ? new Uint32Array(nTriangle * 3) : new Uint16Array(nTriangle * 3);
            }
        }
    },

    _getCubicCurveApproxStep: function (p0, p1, p2, p3) {
        var len = Lines3D_vec3.dist(p0, p1) + Lines3D_vec3.dist(p2, p1) + Lines3D_vec3.dist(p3, p2);
        var step = 1 / (len + 1) * this.segmentScale;
        return step;
    },

    /**
     * Get vertex count of cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @return number
     */
    getCubicCurveVertexCount: function (p0, p1, p2, p3) {
        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);
        var segCount = Math.ceil(1 / step);
        if (!this.useNativeLine) {
            return segCount * 2 + 2;
        }
        else {
            return segCount * 2;
        }
    },

    /**
     * Get face count of cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @return number
     */
    getCubicCurveTriangleCount: function (p0, p1, p2, p3) {
        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);
        var segCount = Math.ceil(1 / step);
        if (!this.useNativeLine) {
            return segCount * 2;
        }
        else {
            return 0;
        }
    },

    /**
     * Get vertex count of line
     * @return {number}
     */
    getLineVertexCount: function () {
        return this.getPolylineVertexCount(sampleLinePoints);
    },

    /**
     * Get face count of line
     * @return {number}
     */
    getLineTriangleCount: function () {
        return this.getPolylineTriangleCount(sampleLinePoints);
    },

    /**
     * Get how many vertices will polyline take.
     * @type {number|Array} points Can be a 1d/2d list of points, or a number of points amount.
     * @return {number}
     */
    getPolylineVertexCount: function (points) {
        var pointsLen;
        if (typeof points === 'number') {
            pointsLen = points;
        }
        else {
            var is2DArray = typeof points[0] !== 'number';
            pointsLen = is2DArray ? points.length : (points.length / 3);
        }
        return !this.useNativeLine ? ((pointsLen - 1) * 2 + 2) : (pointsLen - 1) * 2;
    },

    /**
     * Get how many triangles will polyline take.
     * @type {number|Array} points Can be a 1d/2d list of points, or a number of points amount.
     * @return {number}
     */
    getPolylineTriangleCount: function (points) {
        var pointsLen;
        if (typeof points === 'number') {
            pointsLen = points;
        }
        else {
            var is2DArray = typeof points[0] !== 'number';
            pointsLen = is2DArray ? points.length : (points.length / 3);
        }
        return !this.useNativeLine ? Math.max(pointsLen - 1, 0) * 2 : 0;
    },

    /**
     * Add a cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @param {Array.<number>} color
     * @param {number} [lineWidth=1]
     */
    addCubicCurve: function (p0, p1, p2, p3, color, lineWidth) {
        if (lineWidth == null) {
            lineWidth = 1;
        }
        // incremental interpolation
        // http://antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
        var x0 = p0[0], y0 = p0[1], z0 = p0[2];
        var x1 = p1[0], y1 = p1[1], z1 = p1[2];
        var x2 = p2[0], y2 = p2[1], z2 = p2[2];
        var x3 = p3[0], y3 = p3[1], z3 = p3[2];

        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);

        var step2 = step * step;
        var step3 = step2 * step;

        var pre1 = 3.0 * step;
        var pre2 = 3.0 * step2;
        var pre4 = 6.0 * step2;
        var pre5 = 6.0 * step3;

        var tmp1x = x0 - x1 * 2.0 + x2;
        var tmp1y = y0 - y1 * 2.0 + y2;
        var tmp1z = z0 - z1 * 2.0 + z2;

        var tmp2x = (x1 - x2) * 3.0 - x0 + x3;
        var tmp2y = (y1 - y2) * 3.0 - y0 + y3;
        var tmp2z = (z1 - z2) * 3.0 - z0 + z3;

        var fx = x0;
        var fy = y0;
        var fz = z0;

        var dfx = (x1 - x0) * pre1 + tmp1x * pre2 + tmp2x * step3;
        var dfy = (y1 - y0) * pre1 + tmp1y * pre2 + tmp2y * step3;
        var dfz = (z1 - z0) * pre1 + tmp1z * pre2 + tmp2z * step3;

        var ddfx = tmp1x * pre4 + tmp2x * pre5;
        var ddfy = tmp1y * pre4 + tmp2y * pre5;
        var ddfz = tmp1z * pre4 + tmp2z * pre5;

        var dddfx = tmp2x * pre5;
        var dddfy = tmp2y * pre5;
        var dddfz = tmp2z * pre5;

        var t = 0;

        var k = 0;
        var segCount = Math.ceil(1 / step);

        var points = new Float32Array((segCount + 1) * 3);
        var points = [];
        var offset = 0;
        for (var k = 0; k < segCount + 1; k++) {
            points[offset++] = fx;
            points[offset++] = fy;
            points[offset++] = fz;

            fx += dfx; fy += dfy; fz += dfz;
            dfx += ddfx; dfy += ddfy; dfz += ddfz;
            ddfx += dddfx; ddfy += dddfy; ddfz += dddfz;
            t += step;

            if (t > 1) {
                fx = dfx > 0 ? Math.min(fx, x3) : Math.max(fx, x3);
                fy = dfy > 0 ? Math.min(fy, y3) : Math.max(fy, y3);
                fz = dfz > 0 ? Math.min(fz, z3) : Math.max(fz, z3);
            }
        }

        return this.addPolyline(points, color, lineWidth);
    },

    /**
     * Add a straight line
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} color
     * @param {number} [lineWidth=1]
     */
    addLine: function (p0, p1, color, lineWidth) {
        return this.addPolyline([p0, p1], color, lineWidth);
    },

    /**
     * Add a straight line
     * @param {Array.<Array> | Array.<number>} points
     * @param {Array.<number> | Array.<Array>} color
     * @param {number} [lineWidth=1]
     * @param {number} [startOffset=0]
     * @param {number} [pointsCount] Default to be amount of points in the first argument
     */
    addPolyline: function (points, color, lineWidth, startOffset, pointsCount) {
        if (!points.length) {
            return;
        }
        var is2DArray = typeof points[0] !== 'number';
        if (pointsCount == null) {
            pointsCount = is2DArray ? points.length : points.length / 3;
        }
        if (pointsCount < 2) {
            return;
        }
        if (startOffset == null) {
            startOffset = 0;
        }
        if (lineWidth == null) {
            lineWidth = 1;
        }

        this._itemVertexOffsets.push(this._vertexOffset);

        var is2DArray = typeof points[0] !== 'number';
        var notSharingColor = is2DArray
            ? typeof color[0] !== 'number'
            : color.length / 4 === pointsCount;

        var positionAttr = this.attributes.position;
        var positionPrevAttr = this.attributes.positionPrev;
        var positionNextAttr = this.attributes.positionNext;
        var colorAttr = this.attributes.color;
        var offsetAttr = this.attributes.offset;
        var indices = this.indices;

        var vertexOffset = this._vertexOffset;
        var point;
        var pointColor;

        lineWidth = Math.max(lineWidth, 0.01);

        for (var k = startOffset; k < pointsCount; k++) {
            if (is2DArray) {
                point = points[k];
                if (notSharingColor) {
                    pointColor = color[k];
                }
                else {
                    pointColor = color;
                }
            }
            else {
                var k3 = k * 3;
                point = point || [];
                point[0] = points[k3];
                point[1] = points[k3 + 1];
                point[2] = points[k3 + 2];

                if (notSharingColor) {
                    var k4 = k * 4;
                    pointColor = pointColor || [];
                    pointColor[0] = color[k4];
                    pointColor[1] = color[k4 + 1];
                    pointColor[2] = color[k4 + 2];
                    pointColor[3] = color[k4 + 3];
                }
                else {
                    pointColor = color;
                }
            }
            if (!this.useNativeLine) {
                if (k < pointsCount - 1) {
                    // Set to next two points
                    positionPrevAttr.set(vertexOffset + 2, point);
                    positionPrevAttr.set(vertexOffset + 3, point);
                }
                if (k > 0) {
                    // Set to previous two points
                    positionNextAttr.set(vertexOffset - 2, point);
                    positionNextAttr.set(vertexOffset - 1, point);
                }

                positionAttr.set(vertexOffset, point);
                positionAttr.set(vertexOffset + 1, point);

                colorAttr.set(vertexOffset, pointColor);
                colorAttr.set(vertexOffset + 1, pointColor);

                offsetAttr.set(vertexOffset, lineWidth / 2);
                offsetAttr.set(vertexOffset + 1, -lineWidth / 2);

                vertexOffset += 2;
            }
            else {
                if (k > 1) {
                    positionAttr.copy(vertexOffset, vertexOffset - 1);
                    colorAttr.copy(vertexOffset, vertexOffset - 1);
                    vertexOffset++;
                }
            }

            if (!this.useNativeLine) {
                if (k > 0) {
                    var idx3 = this._triangleOffset * 3;
                    var indices = this.indices;
                    // 0-----2
                    // 1-----3
                    // 0->1->2, 1->3->2
                    indices[idx3] = vertexOffset - 4;
                    indices[idx3 + 1] = vertexOffset - 3;
                    indices[idx3 + 2] = vertexOffset - 2;

                    indices[idx3 + 3] = vertexOffset - 3;
                    indices[idx3 + 4] = vertexOffset - 1;
                    indices[idx3 + 5] = vertexOffset - 2;

                    this._triangleOffset += 2;
                }
            }
            else {
                colorAttr.set(vertexOffset, pointColor);
                positionAttr.set(vertexOffset, point);
                vertexOffset++;
            }
        }
        if (!this.useNativeLine) {
            var start = this._vertexOffset;
            var end = this._vertexOffset + pointsCount * 2;
            positionPrevAttr.copy(start, start + 2);
            positionPrevAttr.copy(start + 1, start + 3);
            positionNextAttr.copy(end - 1, end - 3);
            positionNextAttr.copy(end - 2, end - 4);
        }

        this._vertexOffset = vertexOffset;

        return this._vertexOffset;
    },

    /**
     * Set color of single line.
     */
    setItemColor: function (idx, color) {
        var startOffset = this._itemVertexOffsets[idx];
        var endOffset = idx < this._itemVertexOffsets.length - 1 ? this._itemVertexOffsets[idx + 1] : this._vertexOffset;

        for (var i = startOffset; i < endOffset; i++) {
            this.attributes.color.set(i, color);
        }
        this.dirty('color');
    },

    /**
     * @return {number}
     */
    currentTriangleOffset: function () {
        return this._triangleOffset;
    },

    /**
     * @return {number}
     */
    currentVertexOffset: function () {
        return this._vertexOffset;
    }
});

external_echarts_.util.defaults(LinesGeometry.prototype, dynamicConvertMixin);

/* harmony default export */ const Lines3D = (LinesGeometry);
;// CONCATENATED MODULE: ./src/util/ZRTextureAtlasSurface.js
/**
 * Texture Atlas for the sprites.
 * It uses zrender for 2d element management and rendering
 * @module echarts-gl/util/ZRTextureAtlasSurface
 */

// TODO Expand.



function ZRTextureAtlasSurfaceNode(zr, offsetX, offsetY, width, height, gap, dpr) {
    this._zr = zr;

    /**
     * Current cursor x
     * @type {number}
     * @private
     */
    this._x = 0;

    /**
     * Current cursor y
     * @type {number}
     */
    this._y = 0;

    this._rowHeight = 0;
    /**
     * width without dpr.
     * @type {number}
     * @private
     */
    this.width = width;

    /**
     * height without dpr.
     * @type {number}
     * @private
     */
    this.height = height;

    /**
     * offsetX without dpr
     * @type {number}
     */
    this.offsetX = offsetX;
    /**
     * offsetY without dpr
     * @type {number}
     */
    this.offsetY = offsetY;

    this.dpr = dpr;

    this.gap = gap;
}

ZRTextureAtlasSurfaceNode.prototype = {

    constructor: ZRTextureAtlasSurfaceNode,

    clear: function () {
        this._x = 0;
        this._y = 0;
        this._rowHeight = 0;
    },

    /**
     * Add shape to atlas
     * @param {module:zrender/graphic/Displayable} shape
     * @param {number} width
     * @param {number} height
     * @return {Array}
     */
    add: function (el, width, height) {
        // FIXME Text element not consider textAlign and textVerticalAlign.

        // TODO, inner text, shadow
        var rect = el.getBoundingRect();

        // FIXME aspect ratio
        if (width == null) {
            width = rect.width;
        }
        if (height == null) {
            height = rect.height;
        }
        width *= this.dpr;
        height *= this.dpr;

        this._fitElement(el, width, height);

        // var aspect = el.scale[1] / el.scale[0];
        // Adjust aspect ratio to make the text more clearly
        // FIXME If height > width, width is useless ?
        // width = height * aspect;
        // el.position[0] *= aspect;
        // el.scale[0] = el.scale[1];

        var x = this._x;
        var y = this._y;

        var canvasWidth = this.width * this.dpr;
        var canvasHeight = this.height * this.dpr;
        var gap = this.gap;

        if (x + width + gap > canvasWidth) {
            // Change a new row
            x = this._x = 0;
            y += this._rowHeight + gap;
            this._y = y;
            // Reset row height
            this._rowHeight = 0;
        }

        this._x += width + gap;

        this._rowHeight = Math.max(this._rowHeight, height);

        if (y + height + gap > canvasHeight) {
            // There is no space anymore
            return null;
        }

        // Shift the el
        el.x += this.offsetX * this.dpr + x;
        el.y += this.offsetY * this.dpr + y;

        this._zr.add(el);

        var coordsOffset = [
            this.offsetX / this.width,
            this.offsetY / this.height
        ];
        var coords = [
            [x / canvasWidth + coordsOffset[0], y / canvasHeight + coordsOffset[1]],
            [(x + width) / canvasWidth + coordsOffset[0], (y + height) / canvasHeight + coordsOffset[1]]
        ];

        return coords;
    },

    /**
     * Fit element size by correct its position and scaling
     * @param {module:zrender/graphic/Displayable} el
     * @param {number} spriteWidth
     * @param {number} spriteHeight
     */
    _fitElement: function (el, spriteWidth, spriteHeight) {
        // TODO, inner text, shadow
        var rect = el.getBoundingRect();

        var scaleX = spriteWidth / rect.width;
        var scaleY = spriteHeight / rect.height;
        el.x = -rect.x * scaleX;
        el.y = -rect.y * scaleY;
        el.scaleX = scaleX;
        el.scaleY = scaleY;
        el.update();
    }
}
/**
 * constructor
 * @alias module:echarts-gl/util/ZRTextureAtlasSurface
 * @param {number} opt.width
 * @param {number} opt.height
 * @param {number} opt.devicePixelRatio
 * @param {number} opt.gap Gap for safe.
 * @param {Function} opt.onupdate
 */
function ZRTextureAtlasSurface (opt) {

    opt = opt || {};
    opt.width = opt.width || 512;
    opt.height = opt.height || 512;
    opt.devicePixelRatio = opt.devicePixelRatio || 1;
    opt.gap = opt.gap == null ? 2 : opt.gap;

    var canvas = document.createElement('canvas');
    canvas.width = opt.width * opt.devicePixelRatio;
    canvas.height = opt.height * opt.devicePixelRatio;

    this._canvas = canvas;

    this._texture = new src_Texture2D({
        image: canvas,
        flipY: false
    });

    var self = this;
    /**
     * zrender instance in the Chart
     * @type {zrender~ZRender}
     */
    this._zr = external_echarts_.zrender.init(canvas);
    var oldRefreshImmediately = this._zr.refreshImmediately;
    this._zr.refreshImmediately = function () {
        oldRefreshImmediately.call(this);
        self._texture.dirty();
        self.onupdate && self.onupdate();
    };

    this._dpr = opt.devicePixelRatio;

    /**
     * Texture coords map for each sprite image
     * @type {Object}
     */
    this._coords = {};

    this.onupdate = opt.onupdate;

    this._gap = opt.gap;

    // Left sub atlas.
    this._textureAtlasNodes = [new ZRTextureAtlasSurfaceNode(
        this._zr, 0, 0, opt.width, opt.height, this._gap, this._dpr
    )];

    this._nodeWidth = opt.width;
    this._nodeHeight = opt.height;

    this._currentNodeIdx = 0;
}

ZRTextureAtlasSurface.prototype = {

    /**
     * Clear the texture atlas
     */
    clear: function () {

        for (var i = 0; i < this._textureAtlasNodes.length; i++) {
            this._textureAtlasNodes[i].clear();
        }

        this._currentNodeIdx = 0;

        this._zr.clear();
        this._coords = {};
    },

    /**
     * @return {number}
     */
    getWidth: function () {
        return this._width;
    },

    /**
     * @return {number}
     */
    getHeight: function () {
        return this._height;
    },

    /**
     * @return {number}
     */
    getTexture: function () {
        return this._texture;
    },

    /**
     * @return {number}
     */
    getDevicePixelRatio: function () {
        return this._dpr;
    },

    getZr: function () {
        return this._zr;
    },

    _getCurrentNode: function () {
        return this._textureAtlasNodes[this._currentNodeIdx];
    },

    _expand: function () {
        this._currentNodeIdx++;
        if (this._textureAtlasNodes[this._currentNodeIdx]) {
            // Use the node created previously.
            return this._textureAtlasNodes[this._currentNodeIdx];
        }

        var maxSize = 4096 / this._dpr;
        var textureAtlasNodes = this._textureAtlasNodes;
        var nodeLen = textureAtlasNodes.length;
        var offsetX = (nodeLen * this._nodeWidth) % maxSize;
        var offsetY = Math.floor(nodeLen * this._nodeWidth / maxSize) * this._nodeHeight;
        if (offsetY >= maxSize) {
            // Failed if image is too large.
            if (true) {
                console.error('Too much labels. Some will be ignored.');
            }
            return;
        }

        var width = (offsetX + this._nodeWidth) * this._dpr;
        var height = (offsetY + this._nodeHeight) * this._dpr;
        try {
            // Resize will error in node.
            this._zr.resize({
                width: width,
                height: height
            });
        }
        catch (e) {
            this._canvas.width = width;
            this._canvas.height = height;
        }

        var newNode = new ZRTextureAtlasSurfaceNode(
            this._zr, offsetX, offsetY, this._nodeWidth, this._nodeHeight, this._gap, this._dpr
        );
        this._textureAtlasNodes.push(newNode);

        return newNode;
    },

    add: function (el, width, height) {
        if (this._coords[el.id]) {
            if (true) {
                console.warn('Element already been add');
            }
            return this._coords[el.id];
        }
        var coords = this._getCurrentNode().add(el, width, height);
        if (!coords) {
            var newNode = this._expand();
            if (!newNode) {
                // To maximum
                return;
            }
            coords = newNode.add(el, width, height);
        }

        this._coords[el.id] = coords;

        return coords;
    },

    /**
     * Get coord scale after texture atlas is expanded.
     * @return {Array.<number>}
     */
    getCoordsScale: function () {
        var dpr = this._dpr;
        return [this._nodeWidth / this._canvas.width * dpr, this._nodeHeight / this._canvas.height * dpr];
    },

    /**
     * Get texture coords of sprite image
     * @param  {string} id Image id
     * @return {Array}
     */
    getCoords: function (id) {
        return this._coords[id];
    },

    dispose: function () {
        this._zr.dispose();
    }
};

/* harmony default export */ const util_ZRTextureAtlasSurface = (ZRTextureAtlasSurface);
;// CONCATENATED MODULE: ./src/component/common/SceneHelper.js




function SceneHelper() {
}

SceneHelper.prototype = {
    constructor: SceneHelper,

    setScene: function (scene) {
        this._scene = scene;

        if (this._skybox) {
            this._skybox.attachScene(this._scene);
        }
    },

    initLight: function (rootNode) {
        this._lightRoot = rootNode;
        /**
         * @type {clay.light.Directional}
         */
        this.mainLight = new util_graphicGL.DirectionalLight({
            shadowBias: 0.005
        });

        /**
         * @type {clay.light.Ambient}
         */
        this.ambientLight = new util_graphicGL.AmbientLight();

        rootNode.add(this.mainLight);
        rootNode.add(this.ambientLight);
    },

    dispose: function () {
        if (this._lightRoot) {
            this._lightRoot.remove(this.mainLight);
            this._lightRoot.remove(this.ambientLight);
        }
    },

    updateLight: function (componentModel) {

        var mainLight = this.mainLight;
        var ambientLight = this.ambientLight;

        var lightModel = componentModel.getModel('light');
        var mainLightModel = lightModel.getModel('main');
        var ambientLightModel = lightModel.getModel('ambient');

        mainLight.intensity = mainLightModel.get('intensity');
        ambientLight.intensity = ambientLightModel.get('intensity');
        mainLight.color = util_graphicGL.parseColor(mainLightModel.get('color')).slice(0, 3);
        ambientLight.color = util_graphicGL.parseColor(ambientLightModel.get('color')).slice(0, 3);

        var alpha = mainLightModel.get('alpha') || 0;
        var beta = mainLightModel.get('beta') || 0;
        mainLight.position.setArray(util_graphicGL.directionFromAlphaBeta(alpha, beta));
        mainLight.lookAt(util_graphicGL.Vector3.ZERO);

        mainLight.castShadow = mainLightModel.get('shadow');
        mainLight.shadowResolution = util_graphicGL.getShadowResolution(mainLightModel.get('shadowQuality'));
    },

    updateAmbientCubemap: function (renderer, componentModel, api) {
        var ambientCubemapModel = componentModel.getModel('light.ambientCubemap');

        var textureUrl = ambientCubemapModel.get('texture');
        if (textureUrl) {
            this._cubemapLightsCache = this._cubemapLightsCache || {};
            var lights = this._cubemapLightsCache[textureUrl];
            if (!lights) {
                var self = this;
                lights = this._cubemapLightsCache[textureUrl]
                    = util_graphicGL.createAmbientCubemap(ambientCubemapModel.option, renderer, api, function () {
                        // Use prefitered cubemap
                        if (self._isSkyboxFromAmbientCubemap) {
                            self._skybox.setEnvironmentMap(lights.specular.cubemap);
                        }

                        api.getZr().refresh();
                    });
            }
            this._lightRoot.add(lights.diffuse);
            this._lightRoot.add(lights.specular);

            this._currentCubemapLights = lights;
        }
        else if (this._currentCubemapLights) {
            this._lightRoot.remove(this._currentCubemapLights.diffuse);
            this._lightRoot.remove(this._currentCubemapLights.specular);
            this._currentCubemapLights = null;
        }
    },

    updateSkybox: function (renderer, componentModel, api) {
        var environmentUrl = componentModel.get('environment');

        var self = this;
        function getSkybox() {
            self._skybox = self._skybox || new plugin_Skybox();
            return self._skybox;
        }

        var skybox = getSkybox();
        if (environmentUrl && environmentUrl !== 'none') {
            if (environmentUrl === 'auto') {
                this._isSkyboxFromAmbientCubemap = true;
                // Use environment in ambient cubemap
                if (this._currentCubemapLights) {
                    var cubemap = this._currentCubemapLights.specular.cubemap;
                    skybox.setEnvironmentMap(cubemap);
                    if (this._scene) {
                        skybox.attachScene(this._scene);
                    }
                    skybox.material.set('lod', 3);
                }
                else if (this._skybox) {
                    this._skybox.detachScene();
                }
            }
            // Is gradient or color string
            else if ((typeof environmentUrl === 'object' && environmentUrl.colorStops)
                || (typeof environmentUrl === 'string' && external_echarts_.color.parse(environmentUrl))
            ) {
                this._isSkyboxFromAmbientCubemap = false;
                var texture = new util_graphicGL.Texture2D({
                    anisotropic: 8,
                    flipY: false
                });
                skybox.setEnvironmentMap(texture);
                var canvas = texture.image = document.createElement('canvas');
                canvas.width = canvas.height = 16;
                var ctx = canvas.getContext('2d');
                var rect = new external_echarts_.graphic.Rect({
                    shape: { x: 0, y: 0, width: 16, height: 16 },
                    style: { fill: environmentUrl }
                });
                external_echarts_.innerDrawElementOnCanvas(ctx, rect);

                skybox.attachScene(this._scene);
            }
            else {
                this._isSkyboxFromAmbientCubemap = false;
                // Panorama
                var texture = util_graphicGL.loadTexture(environmentUrl, api, {
                    anisotropic: 8,
                    flipY: false
                });
                skybox.setEnvironmentMap(texture);

                skybox.attachScene(this._scene);
            }
        }
        else {
            if (this._skybox) {
                this._skybox.detachScene(this._scene);
            }
            this._skybox = null;
        }

        var coordSys = componentModel.coordinateSystem;
        if (this._skybox) {
            if (coordSys && coordSys.viewGL
                && environmentUrl !== 'auto'
                && !(environmentUrl.match && environmentUrl.match(/.hdr$/))
            ) {
                var srgbDefineMethod = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
                this._skybox.material[srgbDefineMethod]('fragment', 'SRGB_DECODE');
            }
            else {
                this._skybox.material.undefine('fragment', 'SRGB_DECODE');
            }
            // var ambientCubemapUrl = environmentUrl === 'auto'
            //     ? componentModel.get('light.ambientCubemap.texture')
            //     : environmentUrl;
        }
    }
};

/* harmony default export */ const common_SceneHelper = (SceneHelper);
;// CONCATENATED MODULE: ./src/util/geometry/Quads.js
/**
 * @module echarts-gl/util/geometry/QuadsGeometry
 * @author Yi Shen(http://github.com/pissang)
 */





var Quads_vec3 = dep_glmatrix.vec3;

/**
 * @constructor
 * @alias module:echarts-gl/util/geometry/QuadsGeometry
 * @extends clay.Geometry
 */

var QuadsGeometry = src_Geometry.extend(function () {
    return {

        segmentScale: 1,

        /**
         * Need to use mesh to expand lines if lineWidth > MAX_LINE_WIDTH
         */
        useNativeLine: true,

        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 3, 'POSITION'),
            normal: new src_Geometry.Attribute('normal', 'float', 3, 'NORMAL'),
            color: new src_Geometry.Attribute('color', 'float', 4, 'COLOR')
        }
    };
},
/** @lends module: echarts-gl/util/geometry/QuadsGeometry.prototype */
{

    /**
     * Reset offset
     */
    resetOffset: function () {
        this._vertexOffset = 0;
        this._faceOffset = 0;
    },

    /**
     * @param {number} nQuad
     */
    setQuadCount: function (nQuad) {
        var attributes = this.attributes;
        var vertexCount = this.getQuadVertexCount() * nQuad;
        var triangleCount = this.getQuadTriangleCount() * nQuad;
        if (this.vertexCount !== vertexCount) {
            attributes.position.init(vertexCount);
            attributes.normal.init(vertexCount);
            attributes.color.init(vertexCount);
        }
        if (this.triangleCount !== triangleCount) {
            this.indices = vertexCount > 0xffff ? new Uint32Array(triangleCount * 3) : new Uint16Array(triangleCount * 3);
        }
    },

    getQuadVertexCount: function () {
        return 4;
    },

    getQuadTriangleCount: function () {
        return 2;
    },

    /**
     * Add a quad, which in following order:
     * 0-----1
     * 3-----2
     */
    addQuad: (function () {
        var a = Quads_vec3.create();
        var b = Quads_vec3.create();
        var normal = Quads_vec3.create();
        var indices = [0, 3, 1, 3, 2, 1];
        return function (coords,  color) {
            var positionAttr = this.attributes.position;
            var normalAttr = this.attributes.normal;
            var colorAttr = this.attributes.color;

            Quads_vec3.sub(a, coords[1], coords[0]);
            Quads_vec3.sub(b, coords[2], coords[1]);
            Quads_vec3.cross(normal, a, b);
            Quads_vec3.normalize(normal, normal);

            for (var i = 0; i < 4; i++) {
                positionAttr.set(this._vertexOffset + i, coords[i]);
                colorAttr.set(this._vertexOffset + i, color);
                normalAttr.set(this._vertexOffset + i, normal);
            }
            var idx = this._faceOffset * 3;
            for (var i = 0; i < 6; i++) {
                this.indices[idx + i] = indices[i] + this._vertexOffset;
            }
            this._vertexOffset += 4;
            this._faceOffset += 2;
        };
    })()
});

external_echarts_.util.defaults(QuadsGeometry.prototype, dynamicConvertMixin);

/* harmony default export */ const Quads = (QuadsGeometry);
;// CONCATENATED MODULE: ./src/component/grid3D/Grid3DFace.js





var Grid3DFace_firstNotNull = util_retrieve.firstNotNull;

var dimIndicesMap = {
    // Left to right
    x: 0,
    // Far to near
    y: 2,
    // Bottom to up
    z: 1
};

function updateFacePlane(node, plane, otherAxis, dir) {
    var coord = [0, 0, 0];
    var distance = dir < 0 ? otherAxis.getExtentMin() : otherAxis.getExtentMax();
    coord[dimIndicesMap[otherAxis.dim]] = distance;
    node.position.setArray(coord);
    node.rotation.identity();

    // Negative distance because on the opposite of normal direction.
    plane.distance = -Math.abs(distance);
    plane.normal.set(0, 0, 0);
    if (otherAxis.dim === 'x') {
        node.rotation.rotateY(dir * Math.PI / 2);
        plane.normal.x = -dir;
    }
    else if (otherAxis.dim === 'z') {
        node.rotation.rotateX(-dir * Math.PI / 2);
        plane.normal.y = -dir;
    }
    else {
        if (dir > 0) {
            node.rotation.rotateY(Math.PI);
        }
        plane.normal.z = -dir;
    }
}


function Grid3DFace(faceInfo, linesMaterial, quadsMaterial) {
    this.rootNode = new util_graphicGL.Node();

    var linesMesh = new util_graphicGL.Mesh({
        geometry: new Lines3D({ useNativeLine: false }),
        material: linesMaterial,
        castShadow: false,
        ignorePicking: true,
        $ignorePicking: true,
        renderOrder: 1
    });
    var quadsMesh = new util_graphicGL.Mesh({
        geometry: new Quads(),
        material: quadsMaterial,
        castShadow: false,
        culling: false,
        ignorePicking: true,
        $ignorePicking: true,
        renderOrder: 0
    });
    // Quads are behind lines.
    this.rootNode.add(quadsMesh);
    this.rootNode.add(linesMesh);

    this.faceInfo = faceInfo;
    this.plane =new util_graphicGL.Plane();
    this.linesMesh =linesMesh;
    this.quadsMesh =quadsMesh;
}

Grid3DFace.prototype.update = function (grid3DModel, ecModel, api) {
    var cartesian = grid3DModel.coordinateSystem;
    var axes = [
        cartesian.getAxis(this.faceInfo[0]),
        cartesian.getAxis(this.faceInfo[1])
    ];
    var lineGeometry = this.linesMesh.geometry;
    var quadsGeometry = this.quadsMesh.geometry;

    lineGeometry.convertToDynamicArray(true);
    quadsGeometry.convertToDynamicArray(true);
    this._updateSplitLines(lineGeometry, axes, grid3DModel, api);
    this._udpateSplitAreas(quadsGeometry, axes, grid3DModel, api);
    lineGeometry.convertToTypedArray();
    quadsGeometry.convertToTypedArray();


    var otherAxis = cartesian.getAxis(this.faceInfo[2]);
    updateFacePlane(this.rootNode, this.plane, otherAxis, this.faceInfo[3]);
};

Grid3DFace.prototype._updateSplitLines = function (geometry, axes, grid3DModel, api) {
    var dpr = api.getDevicePixelRatio();
    axes.forEach(function (axis, idx) {
        var axisModel = axis.model;
        var otherExtent = axes[1 - idx].getExtent();

        if (axis.scale.isBlank()) {
            return;
        }

        var splitLineModel = axisModel.getModel('splitLine', grid3DModel.getModel('splitLine'));
        // Render splitLines
        if (splitLineModel.get('show')) {
            var lineStyleModel = splitLineModel.getModel('lineStyle');
            var lineColors = lineStyleModel.get('color');
            var opacity = Grid3DFace_firstNotNull(lineStyleModel.get('opacity'), 1.0);
            var lineWidth = Grid3DFace_firstNotNull(lineStyleModel.get('width'), 1.0);

            lineColors = external_echarts_.util.isArray(lineColors) ? lineColors : [lineColors];

            var ticksCoords = axis.getTicksCoords({
                tickModel: splitLineModel
            });

            var count = 0;
            for (var i = 0; i < ticksCoords.length; i++) {
                var tickCoord = ticksCoords[i].coord;
                var lineColor = util_graphicGL.parseColor(lineColors[count % lineColors.length]);
                lineColor[3] *= opacity;

                var p0 = [0, 0, 0]; var p1 = [0, 0, 0];
                // 0 - x, 1 - y
                p0[idx] = p1[idx] = tickCoord;
                p0[1 - idx] = otherExtent[0];
                p1[1 - idx] = otherExtent[1];

                geometry.addLine(p0, p1, lineColor, lineWidth * dpr);

                count++;
            }
        }
    });
};

Grid3DFace.prototype._udpateSplitAreas = function (geometry, axes, grid3DModel, api) {
    axes.forEach(function (axis, idx) {
        var axisModel = axis.model;
        var otherExtent = axes[1 - idx].getExtent();

        if (axis.scale.isBlank()) {
            return;
        }

        var splitAreaModel = axisModel.getModel('splitArea', grid3DModel.getModel('splitArea'));
        // Render splitAreas
        if (splitAreaModel.get('show')) {
            var areaStyleModel = splitAreaModel.getModel('areaStyle');
            var colors = areaStyleModel.get('color');
            var opacity = Grid3DFace_firstNotNull(areaStyleModel.get('opacity'), 1.0);

            colors = external_echarts_.util.isArray(colors) ? colors : [colors];

            var ticksCoords = axis.getTicksCoords({
                tickModel: splitAreaModel,
                clamp: true
            });

            var count = 0;
            var prevP0 = [0, 0, 0];
            var prevP1 = [0, 0, 0];
            // 0 - x, 1 - y
            for (var i = 0; i < ticksCoords.length; i++) {
                var tickCoord = ticksCoords[i].coord;

                var p0 = [0, 0, 0]; var p1 = [0, 0, 0];
                // 0 - x, 1 - y
                p0[idx] = p1[idx] = tickCoord;
                p0[1 - idx] = otherExtent[0];
                p1[1 - idx] = otherExtent[1];

                if (i === 0) {
                    prevP0 = p0;
                    prevP1 = p1;
                    continue;
                }

                var color = util_graphicGL.parseColor(colors[count % colors.length]);
                color[3] *= opacity;
                geometry.addQuad([prevP0, p0, p1, prevP1], color);

                prevP0 = p0;
                prevP1 = p1;

                count++;
            }
        }
    });
};

/* harmony default export */ const grid3D_Grid3DFace = (Grid3DFace);
;// CONCATENATED MODULE: ./src/util/geometry/Sprites.js
/**
 * Geometry collecting sprites
 *
 * @module echarts-gl/util/geometry/Sprites
 * @author Yi Shen(https://github.com/pissang)
 */




var squareTriangles = [
    0, 1, 2, 0, 2, 3
];

var SpritesGeometry = src_Geometry.extend(function () {
    return {
        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 3, 'POSITION'),
            texcoord: new src_Geometry.Attribute('texcoord', 'float', 2, 'TEXCOORD_0'),
            offset: new src_Geometry.Attribute('offset', 'float', 2),
            color: new src_Geometry.Attribute('color', 'float', 4, 'COLOR')
        }
    };
}, {
    resetOffset: function () {
        this._vertexOffset = 0;
        this._faceOffset = 0;
    },
    setSpriteCount: function (spriteCount) {
        this._spriteCount = spriteCount;

        var vertexCount = spriteCount * 4;
        var triangleCount = spriteCount * 2;

        if (this.vertexCount !== vertexCount) {
            this.attributes.position.init(vertexCount);
            this.attributes.offset.init(vertexCount);
            this.attributes.color.init(vertexCount);
        }
        if (this.triangleCount !== triangleCount) {
            this.indices = vertexCount > 0xffff ? new Uint32Array(triangleCount * 3) : new Uint16Array(triangleCount * 3);
        }
    },

    setSpriteAlign: function (spriteOffset, size, align, verticalAlign, margin) {
        if (align == null) {
            align = 'left';
        }
        if (verticalAlign == null) {
            verticalAlign = 'top';
        }

        var leftOffset, topOffset, rightOffset, bottomOffset;
        margin = margin || 0;
        switch (align) {
            case 'left':
                leftOffset = margin;
                rightOffset = size[0] + margin;
                break;
            case 'center':
            case 'middle':
                leftOffset = -size[0] / 2;
                rightOffset = size[0] / 2;
                break;
            case 'right':
                leftOffset = -size[0] - margin;
                rightOffset = -margin;
                break;
        }
        switch (verticalAlign) {
            case 'bottom':
                topOffset = margin;
                bottomOffset = size[1] + margin;
                break;
            case 'middle':
                topOffset = -size[1] / 2;
                bottomOffset = size[1] / 2;
                break;
            case 'top':
                topOffset = -size[1] - margin;
                bottomOffset = -margin;
                break;
        }
        // 3----2
        // 0----1
        var vertexOffset = spriteOffset * 4;
        var offsetAttr = this.attributes.offset;
        offsetAttr.set(vertexOffset, [leftOffset, bottomOffset]);
        offsetAttr.set(vertexOffset + 1, [rightOffset, bottomOffset]);
        offsetAttr.set(vertexOffset + 2, [rightOffset, topOffset]);
        offsetAttr.set(vertexOffset + 3, [leftOffset, topOffset]);
    },
    /**
     * Add sprite
     * @param {Array.<number>} position
     * @param {Array.<number>} size [width, height]
     * @param {Array.<Array>} coords [leftBottom, rightTop]
     * @param {string} [align='left'] 'left' 'center' 'right'
     * @param {string} [verticalAlign='top'] 'top' 'middle' 'bottom'
     * @param {number} [screenMargin=0]
     */
    addSprite: function (position, size, coords, align, verticalAlign, screenMargin) {
        var vertexOffset = this._vertexOffset;
        this.setSprite(
            this._vertexOffset / 4, position, size, coords, align, verticalAlign, screenMargin
        )
        for (var i = 0; i < squareTriangles.length; i++) {
            this.indices[this._faceOffset * 3 + i] = squareTriangles[i] + vertexOffset;
        }
        this._faceOffset += 2;
        this._vertexOffset += 4;

        return vertexOffset / 4;
    },

    setSprite: function (spriteOffset, position, size, coords, align, verticalAlign, screenMargin) {
        var vertexOffset = spriteOffset * 4;

        var attributes = this.attributes;
        for (var i = 0; i < 4; i++) {
            attributes.position.set(vertexOffset + i, position);
        }
        // 3----2
        // 0----1
        var texcoordAttr = attributes.texcoord;

        texcoordAttr.set(vertexOffset, [coords[0][0], coords[0][1]]);
        texcoordAttr.set(vertexOffset + 1, [coords[1][0], coords[0][1]]);
        texcoordAttr.set(vertexOffset + 2, [coords[1][0], coords[1][1]]);
        texcoordAttr.set(vertexOffset + 3, [coords[0][0], coords[1][1]]);

        this.setSpriteAlign(spriteOffset, size, align, verticalAlign, screenMargin);
    }
});

external_echarts_.util.defaults(SpritesGeometry.prototype, dynamicConvertMixin);

/* harmony default export */ const Sprites = (SpritesGeometry);
;// CONCATENATED MODULE: ./src/util/shader/labels.glsl.js
/* harmony default export */ const labels_glsl = ("@export ecgl.labels.vertex\n\nattribute vec3 position: POSITION;\nattribute vec2 texcoord: TEXCOORD_0;\nattribute vec2 offset;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec4 viewport : VIEWPORT;\n\nvarying vec2 v_Texcoord;\n\nvoid main()\n{\n vec4 proj = worldViewProjection * vec4(position, 1.0);\n\n vec2 screen = (proj.xy / abs(proj.w) + 1.0) * 0.5 * viewport.zw;\n\n screen += offset;\n\n proj.xy = (screen / viewport.zw - 0.5) * 2.0 * abs(proj.w);\n gl_Position = proj;\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n v_Texcoord = texcoord;\n}\n@end\n\n\n@export ecgl.labels.fragment\n\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform float alpha : 1.0;\nuniform sampler2D textureAtlas;\nuniform vec2 uvScale: [1.0, 1.0];\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\nvarying float v_Miter;\n\nvarying vec2 v_Texcoord;\n\nvoid main()\n{\n gl_FragColor = vec4(color, alpha) * texture2D(textureAtlas, v_Texcoord * uvScale);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n}\n\n@end");

;// CONCATENATED MODULE: ./src/util/mesh/LabelsMesh.js




util_graphicGL.Shader.import(labels_glsl);

/* harmony default export */ const LabelsMesh = (util_graphicGL.Mesh.extend(function () {
    var geometry = new Sprites({
        dynamic: true
    });
    var material = new util_graphicGL.Material({
        shader: util_graphicGL.createShader('ecgl.labels'),
        transparent: true,
        depthMask: false
    });

    return {
        geometry: geometry,
        material: material,
        culling: false,
        castShadow: false,
        ignorePicking: true
    };
}));
;// CONCATENATED MODULE: ./src/component/grid3D/Grid3DAxis.js








var Grid3DAxis_firstNotNull = util_retrieve.firstNotNull;

var Grid3DAxis_dimIndicesMap = {
    // Left to right
    x: 0,
    // Far to near
    y: 2,
    // Bottom to up
    z: 1
};

function Grid3DAxis(dim, linesMaterial) {
    var linesMesh = new util_graphicGL.Mesh({
        geometry: new Lines3D({ useNativeLine: false }),
        material: linesMaterial,
        castShadow: false,
        ignorePicking: true, renderOrder: 2
    });
    var axisLabelsMesh = new LabelsMesh();
    axisLabelsMesh.material.depthMask = false;

    var rootNode = new util_graphicGL.Node();
    rootNode.add(linesMesh);
    rootNode.add(axisLabelsMesh);

    this.rootNode = rootNode;
    this.dim = dim;

    this.linesMesh = linesMesh;
    this.labelsMesh = axisLabelsMesh;
    this.axisLineCoords = null;
    this.labelElements = [];
}

var otherDim = {
    x: 'y', y: 'x', z: 'y'
};
Grid3DAxis.prototype.update = function (
    grid3DModel, axisLabelSurface, api
) {
    var cartesian = grid3DModel.coordinateSystem;
    var axis = cartesian.getAxis(this.dim);

    var linesGeo = this.linesMesh.geometry;
    var labelsGeo = this.labelsMesh.geometry;
    linesGeo.convertToDynamicArray(true);
    labelsGeo.convertToDynamicArray(true);
    var axisModel = axis.model;
    var extent = axis.getExtent();

    var dpr = api.getDevicePixelRatio();
    var axisLineModel = axisModel.getModel('axisLine', grid3DModel.getModel('axisLine'));
    var axisTickModel = axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));
    var axisLabelModel = axisModel.getModel('axisLabel', grid3DModel.getModel('axisLabel'));
    var axisLineColor = axisLineModel.get('lineStyle.color');
    // Render axisLine
    if (axisLineModel.get('show')) {
        var axisLineStyleModel = axisLineModel.getModel('lineStyle');
        var p0 = [0, 0, 0]; var p1 = [0, 0, 0];
        var idx = Grid3DAxis_dimIndicesMap[axis.dim];
        p0[idx] = extent[0];
        p1[idx] = extent[1];

        // Save some useful info.
        this.axisLineCoords =[p0, p1];

        var color = util_graphicGL.parseColor(axisLineColor);
        var lineWidth = Grid3DAxis_firstNotNull(axisLineStyleModel.get('width'), 1.0);
        var opacity = Grid3DAxis_firstNotNull(axisLineStyleModel.get('opacity'), 1.0);
        color[3] *= opacity;
        linesGeo.addLine(p0, p1, color, lineWidth * dpr);
    }
    // Render axis ticksCoords
    if (axisTickModel.get('show')) {
        var lineStyleModel = axisTickModel.getModel('lineStyle');
        var lineColor = util_graphicGL.parseColor(
            Grid3DAxis_firstNotNull(lineStyleModel.get('color'), axisLineColor)
        );
        var lineWidth = Grid3DAxis_firstNotNull(lineStyleModel.get('width'), 1.0);
        lineColor[3] *= Grid3DAxis_firstNotNull(lineStyleModel.get('opacity'), 1.0);
        var ticksCoords = axis.getTicksCoords();
        var tickLength = axisTickModel.get('length');

        for (var i = 0; i < ticksCoords.length; i++) {
            var tickCoord = ticksCoords[i].coord;

            var p0 = [0, 0, 0]; var p1 = [0, 0, 0];
            var idx = Grid3DAxis_dimIndicesMap[axis.dim];
            var otherIdx = Grid3DAxis_dimIndicesMap[otherDim[axis.dim]];
            // 0 : x, 1 : y
            p0[idx] = p1[idx] = tickCoord;
            p1[otherIdx] = tickLength;

            linesGeo.addLine(p0, p1, lineColor, lineWidth * dpr);
        }
    }

    this.labelElements = [];
    var dpr = api.getDevicePixelRatio();
    if (axisLabelModel.get('show')) {
        var ticksCoords = axis.getTicksCoords();
        var categoryData = axisModel.get('data');

        var labelMargin = axisLabelModel.get('margin');
        var labels = axis.getViewLabels();

        for (var i = 0; i < labels.length; i++) {
            var tickValue = labels[i].tickValue;
            var formattedLabel = labels[i].formattedLabel;
            var rawLabel = labels[i].rawLabel;

            var tickCoord = axis.dataToCoord(tickValue);

            var p = [0, 0, 0];
            var idx = Grid3DAxis_dimIndicesMap[axis.dim];
            var otherIdx = Grid3DAxis_dimIndicesMap[otherDim[axis.dim]];
            // 0 : x, 1 : y
            p[idx] = p[idx] = tickCoord;
            p[otherIdx] = labelMargin;

            var itemTextStyleModel = axisLabelModel;
            if (categoryData && categoryData[tickValue] && categoryData[tickValue].textStyle) {
                itemTextStyleModel = new external_echarts_.Model(
                    categoryData[tickValue].textStyle, axisLabelModel, axisModel.ecModel
                );
            }
            var textColor = Grid3DAxis_firstNotNull(itemTextStyleModel.get('color'), axisLineColor);

            var textEl = new external_echarts_.graphic.Text({
                style: createTextStyle(itemTextStyleModel, {
                    text: formattedLabel,
                    fill: typeof textColor === 'function'
                        ? textColor(
                            // (1) In category axis with data zoom, tick is not the original
                            // index of axis.data. So tick should not be exposed to user
                            // in category axis.
                            // (2) Compatible with previous version, which always returns labelStr.
                            // But in interval scale labelStr is like '223,445', which maked
                            // user repalce ','. So we modify it to return original val but remain
                            // it as 'string' to avoid error in replacing.
                            axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue,
                            i
                        )
                        : textColor,
                    verticalAlign: 'top',
                    align: 'left'
                })
            });

            var coords = axisLabelSurface.add(textEl);
            var rect = textEl.getBoundingRect();
            labelsGeo.addSprite(p, [rect.width * dpr, rect.height * dpr], coords);

            this.labelElements.push(textEl);
        }
    }

    if (axisModel.get('name')) {
        var nameTextStyleModel = axisModel.getModel('nameTextStyle');
        var p = [0, 0, 0];
        var idx = Grid3DAxis_dimIndicesMap[axis.dim];
        var otherIdx = Grid3DAxis_dimIndicesMap[otherDim[axis.dim]];
        var labelColor = Grid3DAxis_firstNotNull(nameTextStyleModel.get('color'), axisLineColor);
        var strokeColor = nameTextStyleModel.get('borderColor');
        var lineWidth = nameTextStyleModel.get('borderWidth');
        // TODO start and end
        p[idx] = p[idx] = (extent[0] + extent[1]) / 2;
        p[otherIdx] = axisModel.get('nameGap');

        var textEl = new external_echarts_.graphic.Text({
            style: createTextStyle(nameTextStyleModel, {
                text: axisModel.get('name'),
                fill: labelColor,
                stroke: strokeColor,
                lineWidth: lineWidth
            })
        });

        var coords = axisLabelSurface.add(textEl);
        var rect = textEl.getBoundingRect();
        labelsGeo.addSprite(p, [rect.width * dpr, rect.height * dpr], coords);

        textEl.__idx = this.labelElements.length;
        this.nameLabelElement = textEl;
    }

    this.labelsMesh.material.set('textureAtlas', axisLabelSurface.getTexture());
    this.labelsMesh.material.set('uvScale', axisLabelSurface.getCoordsScale());

    linesGeo.convertToTypedArray();
    labelsGeo.convertToTypedArray();
};

Grid3DAxis.prototype.setSpriteAlign = function (textAlign, textVerticalAlign, api) {
    var dpr = api.getDevicePixelRatio();
    var labelGeo = this.labelsMesh.geometry;
    for (var i = 0; i < this.labelElements.length; i++) {
        var labelEl = this.labelElements[i];
        var rect = labelEl.getBoundingRect();

        labelGeo.setSpriteAlign(i, [rect.width * dpr, rect.height * dpr], textAlign, textVerticalAlign);
    }
    // name label
    var nameLabelEl = this.nameLabelElement;
    if (nameLabelEl) {
        var rect = nameLabelEl.getBoundingRect();
        labelGeo.setSpriteAlign(nameLabelEl.__idx, [rect.width * dpr, rect.height * dpr], textAlign, textVerticalAlign);
        labelGeo.dirty();
    }

    this.textAlign = textAlign;
    this.textVerticalAlign = textVerticalAlign;
};

/* harmony default export */ const grid3D_Grid3DAxis = (Grid3DAxis);
;// CONCATENATED MODULE: ./src/util/shader/lines3D.glsl.js
/* harmony default export */ const lines3D_glsl = ("@export ecgl.lines3D.vertex\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nattribute vec3 position: POSITION;\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n\nvoid main()\n{\n gl_Position = worldViewProjection * vec4(position, 1.0);\n v_Color = a_Color;\n}\n\n@end\n\n@export ecgl.lines3D.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nvarying vec4 v_Color;\n\n@import clay.util.srgb\n\nvoid main()\n{\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(color * v_Color);\n#else\n gl_FragColor = color * v_Color;\n#endif\n}\n@end\n\n\n\n@export ecgl.lines3D.clipNear\n\nvec4 clipNear(vec4 p1, vec4 p2) {\n float n = (p1.w - near) / (p1.w - p2.w);\n return vec4(mix(p1.xy, p2.xy, n), -near, near);\n}\n\n@end\n\n@export ecgl.lines3D.expandLine\n#ifdef VERTEX_ANIMATION\n vec4 prevProj = worldViewProjection * vec4(mix(prevPositionPrev, positionPrev, percent), 1.0);\n vec4 currProj = worldViewProjection * vec4(mix(prevPosition, position, percent), 1.0);\n vec4 nextProj = worldViewProjection * vec4(mix(prevPositionNext, positionNext, percent), 1.0);\n#else\n vec4 prevProj = worldViewProjection * vec4(positionPrev, 1.0);\n vec4 currProj = worldViewProjection * vec4(position, 1.0);\n vec4 nextProj = worldViewProjection * vec4(positionNext, 1.0);\n#endif\n\n if (currProj.w < 0.0) {\n if (nextProj.w > 0.0) {\n currProj = clipNear(currProj, nextProj);\n }\n else if (prevProj.w > 0.0) {\n currProj = clipNear(currProj, prevProj);\n }\n }\n\n vec2 prevScreen = (prevProj.xy / abs(prevProj.w) + 1.0) * 0.5 * viewport.zw;\n vec2 currScreen = (currProj.xy / abs(currProj.w) + 1.0) * 0.5 * viewport.zw;\n vec2 nextScreen = (nextProj.xy / abs(nextProj.w) + 1.0) * 0.5 * viewport.zw;\n\n vec2 dir;\n float len = offset;\n if (position == positionPrev) {\n dir = normalize(nextScreen - currScreen);\n }\n else if (position == positionNext) {\n dir = normalize(currScreen - prevScreen);\n }\n else {\n vec2 dirA = normalize(currScreen - prevScreen);\n vec2 dirB = normalize(nextScreen - currScreen);\n\n vec2 tanget = normalize(dirA + dirB);\n\n float miter = 1.0 / max(dot(tanget, dirA), 0.5);\n len *= miter;\n dir = tanget;\n }\n\n dir = vec2(-dir.y, dir.x) * len;\n currScreen += dir;\n\n currProj.xy = (currScreen / viewport.zw - 0.5) * 2.0 * abs(currProj.w);\n@end\n\n\n@export ecgl.meshLines3D.vertex\n\nattribute vec3 position: POSITION;\nattribute vec3 positionPrev;\nattribute vec3 positionNext;\nattribute float offset;\nattribute vec4 a_Color : COLOR;\n\n#ifdef VERTEX_ANIMATION\nattribute vec3 prevPosition;\nattribute vec3 prevPositionPrev;\nattribute vec3 prevPositionNext;\nuniform float percent : 1.0;\n#endif\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec4 viewport : VIEWPORT;\nuniform float near : NEAR;\n\nvarying vec4 v_Color;\n\n@import ecgl.common.wireframe.vertexHeader\n\n@import ecgl.lines3D.clipNear\n\nvoid main()\n{\n @import ecgl.lines3D.expandLine\n\n gl_Position = currProj;\n\n v_Color = a_Color;\n\n @import ecgl.common.wireframe.vertexMain\n}\n@end\n\n\n@export ecgl.meshLines3D.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nvarying vec4 v_Color;\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.util.srgb\n\nvoid main()\n{\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(color * v_Color);\n#else\n gl_FragColor = color * v_Color;\n#endif\n\n @import ecgl.common.wireframe.fragmentMain\n}\n\n@end");

;// CONCATENATED MODULE: ./src/component/grid3D/Grid3DView.js
// TODO orthographic camera







var Grid3DView_firstNotNull = util_retrieve.firstNotNull;







util_graphicGL.Shader.import(lines3D_glsl);

var Grid3DView_dimIndicesMap = {
    // Left to right
    x: 0,
    // Far to near
    y: 2,
    // Bottom to up
    z: 1
};

/* harmony default export */ const Grid3DView = (external_echarts_.ComponentView.extend({

    type: 'grid3D',

    __ecgl__: true,

    init: function (ecModel, api) {

        var FACES = [
            // planeDim0, planeDim1, offsetDim, dir on dim3 axis(gl), plane.
            ['y', 'z', 'x', -1, 'left'],
            ['y', 'z', 'x',  1, 'right'],
            ['x', 'y', 'z', -1, 'bottom'],
            ['x', 'y','z',  1, 'top'],
            ['x', 'z', 'y', -1, 'far'],
            ['x', 'z','y',  1, 'near']
        ];

        var DIMS = ['x', 'y', 'z'];

        var quadsMaterial = new util_graphicGL.Material({
            // transparent: true,
            shader: util_graphicGL.createShader('ecgl.color'),
            depthMask: false,
            transparent: true
        });
        var linesMaterial = new util_graphicGL.Material({
            // transparent: true,
            shader: util_graphicGL.createShader('ecgl.meshLines3D'),
            depthMask: false,
            transparent: true
        });
        quadsMaterial.define('fragment', 'DOUBLE_SIDED');
        quadsMaterial.define('both', 'VERTEX_COLOR');

        this.groupGL = new util_graphicGL.Node();

        this._control = new util_OrbitControl({
            zr: api.getZr()
        });
        this._control.init();

        // Save mesh and other infos for each face.
        this._faces = FACES.map(function (faceInfo) {
            var face = new grid3D_Grid3DFace(faceInfo, linesMaterial, quadsMaterial);
            this.groupGL.add(face.rootNode);
            return face;
        }, this);

        // Save mesh and other infos for each axis.
        this._axes = DIMS.map(function (dim) {
            var axis = new grid3D_Grid3DAxis(dim, linesMaterial);
            this.groupGL.add(axis.rootNode);
            return axis;
        }, this);

        var dpr = api.getDevicePixelRatio();
        // Texture surface for label.
        this._axisLabelSurface = new util_ZRTextureAtlasSurface({
            width: 256, height: 256,
            devicePixelRatio: dpr
        });
        this._axisLabelSurface.onupdate = function () {
            api.getZr().refresh();
        };

        this._axisPointerLineMesh = new util_graphicGL.Mesh({
            geometry: new Lines3D({ useNativeLine: false }),
            material: linesMaterial,
            castShadow: false,
            // PENDING
            ignorePicking: true,
            renderOrder: 3
        });
        this.groupGL.add(this._axisPointerLineMesh);

        this._axisPointerLabelsSurface = new util_ZRTextureAtlasSurface({
            width: 128, height: 128,
            devicePixelRatio: dpr
        });
        this._axisPointerLabelsMesh = new LabelsMesh({
            ignorePicking: true, renderOrder: 4,
            castShadow: false
        });
        this._axisPointerLabelsMesh.material.set('textureAtlas', this._axisPointerLabelsSurface.getTexture());
        this.groupGL.add(this._axisPointerLabelsMesh);

        this._lightRoot = new util_graphicGL.Node();
        this._sceneHelper = new common_SceneHelper();
        this._sceneHelper.initLight(this._lightRoot);
    },

    render: function (grid3DModel, ecModel, api) {

        this._model = grid3DModel;
        this._api = api;

        var cartesian = grid3DModel.coordinateSystem;

        // Always have light.
        cartesian.viewGL.add(this._lightRoot);

        if (grid3DModel.get('show')) {
            cartesian.viewGL.add(this.groupGL);
        }
        else {
            cartesian.viewGL.remove(this.groupGL);
        }

        // cartesian.viewGL.setCameraType(grid3DModel.get('viewControl.projection'));

        var control = this._control;
        control.setViewGL(cartesian.viewGL);

        var viewControlModel = grid3DModel.getModel('viewControl');
        control.setFromViewControlModel(viewControlModel, 0);

        this._axisLabelSurface.clear();

        control.off('update');
        if (grid3DModel.get('show')) {
            this._faces.forEach(function (face) {
                face.update(grid3DModel, ecModel, api);
            }, this);
            this._axes.forEach(function (axis) {
                axis.update(grid3DModel, this._axisLabelSurface, api);
            }, this);
        }

        control.on('update', this._onCameraChange.bind(this, grid3DModel, api), this);

        this._sceneHelper.setScene(cartesian.viewGL.scene);
        this._sceneHelper.updateLight(grid3DModel);

        // Set post effect
        cartesian.viewGL.setPostEffect(grid3DModel.getModel('postEffect'), api);
        cartesian.viewGL.setTemporalSuperSampling(grid3DModel.getModel('temporalSuperSampling'));

        this._initMouseHandler(grid3DModel);
    },

    afterRender: function (grid3DModel, ecModel, api, layerGL) {
        // Create ambient cubemap after render because we need to know the renderer.
        // TODO
        var renderer = layerGL.renderer;

        this._sceneHelper.updateAmbientCubemap(renderer, grid3DModel, api);

        this._sceneHelper.updateSkybox(renderer, grid3DModel, api);
    },

    /**
     * showAxisPointer will be triggered by action.
     */
    showAxisPointer: function (grid3dModel, ecModel, api, payload) {
        this._doShowAxisPointer();
        this._updateAxisPointer(payload.value);
    },

    /**
     * hideAxisPointer will be triggered by action.
     */
    hideAxisPointer: function (grid3dModel, ecModel, api, payload) {
        this._doHideAxisPointer();
    },

    _initMouseHandler: function (grid3DModel) {
        var cartesian = grid3DModel.coordinateSystem;
        var viewGL = cartesian.viewGL;

        // TODO xAxis3D.axisPointer.show ?
        if (grid3DModel.get('show') && grid3DModel.get('axisPointer.show')) {
            viewGL.on('mousemove', this._updateAxisPointerOnMousePosition, this);
        }
        else {
            viewGL.off('mousemove', this._updateAxisPointerOnMousePosition);
        }
    },

    /**
     * Try find and show axisPointer on the intersect point
     * of mouse ray with grid plane.
     */
    _updateAxisPointerOnMousePosition: function (e) {
        // Ignore if mouse is on the element.
        if (e.target) {
            return;
        }
        var grid3DModel = this._model;
        var cartesian = grid3DModel.coordinateSystem;
        var viewGL = cartesian.viewGL;

        var ray = viewGL.castRay(e.offsetX, e.offsetY, new util_graphicGL.Ray());

        var nearestIntersectPoint;
        for (var i = 0; i < this._faces.length; i++) {
            var face = this._faces[i];
            if (face.rootNode.invisible) {
                continue;
            }

            // Plane is not face the camera. flip it
            if (face.plane.normal.dot(viewGL.camera.worldTransform.z) < 0) {
                face.plane.normal.negate();
            }

            var point = ray.intersectPlane(face.plane);
            if (!point) {
                continue;
            }
            var axis0 = cartesian.getAxis(face.faceInfo[0]);
            var axis1 = cartesian.getAxis(face.faceInfo[1]);
            var idx0 = Grid3DView_dimIndicesMap[face.faceInfo[0]];
            var idx1 = Grid3DView_dimIndicesMap[face.faceInfo[1]];
            if (axis0.contain(point.array[idx0]) && axis1.contain(point.array[idx1])) {
                nearestIntersectPoint = point;
            }
        }

        if (nearestIntersectPoint) {
            var data = cartesian.pointToData(nearestIntersectPoint.array, [], true);
            this._updateAxisPointer(data);

            this._doShowAxisPointer();
        }
        else {
            this._doHideAxisPointer();
        }
    },

    _onCameraChange: function (grid3DModel, api) {

        if (grid3DModel.get('show')) {
            this._updateFaceVisibility();
            this._updateAxisLinePosition();
        }

        var control = this._control;

        api.dispatchAction({
            type: 'grid3DChangeCamera',
            alpha: control.getAlpha(),
            beta: control.getBeta(),
            distance: control.getDistance(),
            center: control.getCenter(),
            from: this.uid,
            grid3DId: grid3DModel.id
        });
    },

    /**
     * Update visibility of each face when camera view changed, front face will be invisible.
     * @private
     */
    _updateFaceVisibility: function () {
        var camera = this._control.getCamera();
        var viewSpacePos = new util_graphicGL.Vector3();
        camera.update();
        for (var idx = 0; idx < this._faces.length / 2; idx++) {
            var depths = [];
            for (var k = 0; k < 2; k++) {
                var face = this._faces[idx * 2 + k];
                face.rootNode.getWorldPosition(viewSpacePos);
                viewSpacePos.transformMat4(camera.viewMatrix);
                depths[k] = viewSpacePos.z;
            }
            // Set the front face invisible
            var frontIndex = depths[0] > depths[1] ? 0 : 1;
            var frontFace = this._faces[idx * 2 + frontIndex];
            var backFace = this._faces[idx * 2 + 1 - frontIndex];
            // Update rotation.
            frontFace.rootNode.invisible = true;
            backFace.rootNode.invisible = false;
        }
    },

    /**
     * Update axis line position when camera view changed.
     * @private
     */
    _updateAxisLinePosition: function () {
        // Put xAxis, yAxis on x, y visible plane.
        // Put zAxis on the left.
        // TODO
        var cartesian = this._model.coordinateSystem;
        var xAxis = cartesian.getAxis('x');
        var yAxis = cartesian.getAxis('y');
        var zAxis = cartesian.getAxis('z');
        var top = zAxis.getExtentMax();
        var bottom = zAxis.getExtentMin();
        var left = xAxis.getExtentMin();
        var right = xAxis.getExtentMax();
        var near = yAxis.getExtentMax();
        var far = yAxis.getExtentMin();

        var xAxisNode = this._axes[0].rootNode;
        var yAxisNode = this._axes[1].rootNode;
        var zAxisNode = this._axes[2].rootNode;

        var faces = this._faces;
        // Notice: in cartesian up axis is z, but in webgl up axis is y.
        var xAxisZOffset = (faces[4].rootNode.invisible ? far : near);
        var xAxisYOffset = (faces[2].rootNode.invisible ? top : bottom);
        var yAxisXOffset = (faces[0].rootNode.invisible ? left : right);
        var yAxisYOffset = (faces[2].rootNode.invisible ? top : bottom);
        var zAxisXOffset = (faces[0].rootNode.invisible ? right : left);
        var zAxisZOffset = (faces[4].rootNode.invisible ? far : near);

        xAxisNode.rotation.identity();
        yAxisNode.rotation.identity();
        zAxisNode.rotation.identity();
        if (faces[4].rootNode.invisible) {
            this._axes[0].flipped = true;
            xAxisNode.rotation.rotateX(Math.PI);
        }
        if (faces[0].rootNode.invisible) {
            this._axes[1].flipped = true;
            yAxisNode.rotation.rotateZ(Math.PI);
        }
        if (faces[4].rootNode.invisible) {
            this._axes[2].flipped = true;
            zAxisNode.rotation.rotateY(Math.PI);
        }

        xAxisNode.position.set(0, xAxisYOffset, xAxisZOffset);
        yAxisNode.position.set(yAxisXOffset, yAxisYOffset, 0); // Actually z
        zAxisNode.position.set(zAxisXOffset, 0, zAxisZOffset); // Actually y

        xAxisNode.update();
        yAxisNode.update();
        zAxisNode.update();

        this._updateAxisLabelAlign();
    },

    /**
     * Update label align on axis when axisLine position changed.
     * @private
     */
    _updateAxisLabelAlign: function () {
        // var cartesian = this._model.coordinateSystem;
        var camera = this._control.getCamera();
        var coords = [new util_graphicGL.Vector4(), new util_graphicGL.Vector4()];
        var center = new util_graphicGL.Vector4();
        this.groupGL.getWorldPosition(center);
        center.w = 1.0;
        center.transformMat4(camera.viewMatrix)
            .transformMat4(camera.projectionMatrix);
        center.x /= center.w;
        center.y /= center.w;
        this._axes.forEach(function (axisInfo) {
            var lineCoords = axisInfo.axisLineCoords;
            var labelGeo = axisInfo.labelsMesh.geometry;
            for (var i = 0; i < coords.length; i++) {
                coords[i].setArray(lineCoords[i]);
                coords[i].w = 1.0;
                coords[i].transformMat4(axisInfo.rootNode.worldTransform)
                    .transformMat4(camera.viewMatrix)
                    .transformMat4(camera.projectionMatrix);
                coords[i].x /= coords[i].w;
                coords[i].y /= coords[i].w;
            }
            var dx = coords[1].x - coords[0].x;
            var dy = coords[1].y - coords[0].y;
            var cx = (coords[1].x + coords[0].x) / 2;
            var cy = (coords[1].y + coords[0].y) / 2;
            var textAlign;
            var verticalAlign;
            if (Math.abs(dy / dx) < 0.5) {
                textAlign = 'center';
                verticalAlign = cy > center.y ? 'bottom' : 'top';
            }
            else {
                verticalAlign = 'middle';
                textAlign = cx > center.x ? 'left' : 'right';
            }

            // axis labels
            axisInfo.setSpriteAlign(textAlign, verticalAlign, this._api);
        }, this);
    },

    _doShowAxisPointer: function () {
        if (!this._axisPointerLineMesh.invisible) {
            return;
        }

        this._axisPointerLineMesh.invisible = false;
        this._axisPointerLabelsMesh.invisible = false;
        this._api.getZr().refresh();
    },

    _doHideAxisPointer: function () {
        if (this._axisPointerLineMesh.invisible) {
            return;
        }

        this._axisPointerLineMesh.invisible = true;
        this._axisPointerLabelsMesh.invisible = true;
        this._api.getZr().refresh();
    },
    /**
     * @private updateAxisPointer.
     */
    _updateAxisPointer: function (data) {
        var cartesian = this._model.coordinateSystem;
        var point = cartesian.dataToPoint(data);

        var axisPointerLineMesh = this._axisPointerLineMesh;
        var linesGeo = axisPointerLineMesh.geometry;

        var axisPointerParentModel = this._model.getModel('axisPointer');

        var dpr = this._api.getDevicePixelRatio();
        linesGeo.convertToDynamicArray(true);


        function ifShowAxisPointer(axis) {
            return util_retrieve.firstNotNull(
                axis.model.get('axisPointer.show'),
                axisPointerParentModel.get('show')
            );
        }
        function getAxisColorAndLineWidth(axis) {
            var axisPointerModel = axis.model.getModel('axisPointer', axisPointerParentModel);
            var lineStyleModel = axisPointerModel.getModel('lineStyle');

            var color = util_graphicGL.parseColor(lineStyleModel.get('color'));
            var lineWidth = Grid3DView_firstNotNull(lineStyleModel.get('width'), 1);
            var opacity = Grid3DView_firstNotNull(lineStyleModel.get('opacity'), 1);
            color[3] *= opacity;

            return {
                color: color,
                lineWidth: lineWidth
            };
        }
        for (var k = 0; k < this._faces.length; k++) {
            var face = this._faces[k];
            if (face.rootNode.invisible) {
                continue;
            }

            var faceInfo = face.faceInfo;
            var otherCoord = faceInfo[3] < 0
                ? cartesian.getAxis(faceInfo[2]).getExtentMin()
                : cartesian.getAxis(faceInfo[2]).getExtentMax();
            var otherDimIdx = Grid3DView_dimIndicesMap[faceInfo[2]];

            // Line on face.
            for (var i = 0; i < 2; i++) {
                var dim = faceInfo[i];
                var faceOtherDim = faceInfo[1 - i];
                var axis = cartesian.getAxis(dim);
                var faceOtherAxis = cartesian.getAxis(faceOtherDim);

                if (!ifShowAxisPointer(axis)) {
                    continue;
                }

                var p0 = [0, 0, 0]; var p1 = [0, 0, 0];
                var dimIdx = Grid3DView_dimIndicesMap[dim];
                var faceOtherDimIdx = Grid3DView_dimIndicesMap[faceOtherDim];
                p0[dimIdx] = p1[dimIdx] = point[dimIdx];

                p0[otherDimIdx] = p1[otherDimIdx] = otherCoord;
                p0[faceOtherDimIdx] = faceOtherAxis.getExtentMin();
                p1[faceOtherDimIdx] = faceOtherAxis.getExtentMax();

                var colorAndLineWidth = getAxisColorAndLineWidth(axis);
                linesGeo.addLine(p0, p1, colorAndLineWidth.color, colorAndLineWidth.lineWidth * dpr);
            }

            // Project line.
            if (ifShowAxisPointer(cartesian.getAxis(faceInfo[2]))) {
                var p0 = point.slice();
                var p1 = point.slice();
                p1[otherDimIdx] = otherCoord;
                var colorAndLineWidth = getAxisColorAndLineWidth(cartesian.getAxis(faceInfo[2]));
                linesGeo.addLine(p0, p1, colorAndLineWidth.color, colorAndLineWidth.lineWidth * dpr);
            }
        }
        linesGeo.convertToTypedArray();

        this._updateAxisPointerLabelsMesh(data);

        this._api.getZr().refresh();
    },

    _updateAxisPointerLabelsMesh: function (data) {
        var grid3dModel = this._model;
        var axisPointerLabelsMesh = this._axisPointerLabelsMesh;
        var axisPointerLabelsSurface = this._axisPointerLabelsSurface;
        var cartesian = grid3dModel.coordinateSystem;

        var axisPointerParentModel = grid3dModel.getModel('axisPointer');

        axisPointerLabelsMesh.geometry.convertToDynamicArray(true);
        axisPointerLabelsSurface.clear();

        var otherDim = {
            x: 'y', y: 'x', z: 'y'
        };
        this._axes.forEach(function (axisInfo, idx) {
            var axis = cartesian.getAxis(axisInfo.dim);
            var axisModel = axis.model;
            var axisPointerModel = axisModel.getModel('axisPointer', axisPointerParentModel);
            var labelModel = axisPointerModel.getModel('label');
            var lineColor = axisPointerModel.get('lineStyle.color');
            if (!labelModel.get('show') || !axisPointerModel.get('show')) {
                return;
            }
            var val = data[idx];
            var formatter = labelModel.get('formatter');
            var text = axis.scale.getLabel({ value: val });
            if (formatter != null) {
                text = formatter(text, data);
            }
            else {
                if (axis.scale.type === 'interval' || axis.scale.type === 'log') {
                    var precision = external_echarts_.number.getPrecisionSafe(axis.scale.getTicks()[0]);
                    text = val.toFixed(precision + 2);
                }
            }

            var labelColor = labelModel.get('color');
            var textEl = new external_echarts_.graphic.Text({
                style: createTextStyle(labelModel, {
                    text: text,
                    fill: labelColor || lineColor,
                    align: 'left',
                    verticalAlign: 'top'
                })
            });

            var coords = axisPointerLabelsSurface.add(textEl);
            var rect = textEl.getBoundingRect();
            var dpr = this._api.getDevicePixelRatio();
            var pos = axisInfo.rootNode.position.toArray();
            var otherIdx = Grid3DView_dimIndicesMap[otherDim[axisInfo.dim]];
            pos[otherIdx] += (axisInfo.flipped ? -1 : 1) * labelModel.get('margin');
            pos[Grid3DView_dimIndicesMap[axisInfo.dim]] = axis.dataToCoord(data[idx]);

            axisPointerLabelsMesh.geometry.addSprite(
                pos, [rect.width * dpr, rect.height * dpr], coords,
                axisInfo.textAlign, axisInfo.textVerticalAlign
            );
        }, this);
        axisPointerLabelsSurface.getZr().refreshImmediately();
        axisPointerLabelsMesh.material.set('uvScale', axisPointerLabelsSurface.getCoordsScale());
        axisPointerLabelsMesh.geometry.convertToTypedArray();
    },

    dispose: function () {
        this.groupGL.removeAll();
        this._control.dispose();
        this._axisLabelSurface.dispose();
        this._axisPointerLabelsSurface.dispose();
    }
}));
;// CONCATENATED MODULE: ./node_modules/echarts/lib/coord/cartesian/Cartesian.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


var Cartesian =
/** @class */
function () {
  function Cartesian(name) {
    this.type = 'cartesian';
    this._dimList = [];
    this._axes = {};
    this.name = name || '';
  }

  Cartesian.prototype.getAxis = function (dim) {
    return this._axes[dim];
  };

  Cartesian.prototype.getAxes = function () {
    return map(this._dimList, function (dim) {
      return this._axes[dim];
    }, this);
  };

  Cartesian.prototype.getAxesByScale = function (scaleType) {
    scaleType = scaleType.toLowerCase();
    return filter(this.getAxes(), function (axis) {
      return axis.scale.type === scaleType;
    });
  };

  Cartesian.prototype.addAxis = function (axis) {
    var dim = axis.dim;
    this._axes[dim] = axis;

    this._dimList.push(dim);
  };

  return Cartesian;
}();

;
/* harmony default export */ const cartesian_Cartesian = (Cartesian);
;// CONCATENATED MODULE: ./src/coord/grid3D/Cartesian3D.js



function Cartesian3D(name) {

    cartesian_Cartesian.call(this, name);

    this.type = 'cartesian3D';

    this.dimensions = ['x', 'y', 'z'];

    this.size = [0, 0, 0];
}

Cartesian3D.prototype = {

    constructor: Cartesian3D,


    model: null,

    containPoint: function (point) {
        return this.getAxis('x').contain(point[0])
            && this.getAxis('y').contain(point[2])
            && this.getAxis('z').contain(point[1]);
    },

    containData: function (data) {
        return this.getAxis('x').containData(data[0])
            && this.getAxis('y').containData(data[1])
            && this.getAxis('z').containData(data[2]);
    },

    dataToPoint: function (data, out, clamp) {
        out = out || [];
        out[0] = this.getAxis('x').dataToCoord(data[0], clamp);
        out[2] = this.getAxis('y').dataToCoord(data[1], clamp);
        out[1] = this.getAxis('z').dataToCoord(data[2], clamp);
        return out;
    },

    pointToData: function (point, out, clamp) {
        out = out || [];
        out[0] = this.getAxis('x').coordToData(point[0], clamp);
        out[1] = this.getAxis('y').coordToData(point[2], clamp);
        out[2] = this.getAxis('z').coordToData(point[1], clamp);
        return out;
    }
};

external_echarts_.util.inherits(Cartesian3D, cartesian_Cartesian);

/* harmony default export */ const grid3D_Cartesian3D = (Cartesian3D);
;// CONCATENATED MODULE: ./src/coord/grid3D/Axis3D.js


function Axis3D(dim, scale, extent) {

    external_echarts_.Axis.call(this, dim, scale, extent);
}

Axis3D.prototype = {
    constructor: Axis3D,

    getExtentMin: function () {
        var extent = this._extent;
        return Math.min(extent[0], extent[1]);
    },

    getExtentMax: function () {
        var extent = this._extent;
        return Math.max(extent[0], extent[1]);
    },

    calculateCategoryInterval: function () {
        // TODO consider label length
        return Math.floor(this.scale.count() / 8);
    }
};

external_echarts_.util.inherits(Axis3D, external_echarts_.Axis);

/* harmony default export */ const grid3D_Axis3D = (Axis3D);
;// CONCATENATED MODULE: ./node_modules/echarts/node_modules/tslib/tslib.es6.js
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */

var tslib_es6_extendStatics = function(d, b) {
    tslib_es6_extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
    return tslib_es6_extendStatics(d, b);
};

function tslib_es6_extends(d, b) {
    tslib_es6_extendStatics(d, b);
    function __() { this.constructor = d; }
    d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}

var tslib_es6_assign = function() {
    tslib_es6_assign = Object.assign || function __assign(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
        }
        return t;
    }
    return tslib_es6_assign.apply(this, arguments);
}

function tslib_es6_rest(s, e) {
    var t = {};
    for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
        t[p] = s[p];
    if (s != null && typeof Object.getOwnPropertySymbols === "function")
        for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
            if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
                t[p[i]] = s[p[i]];
        }
    return t;
}

function tslib_es6_decorate(decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
}

function tslib_es6_param(paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
}

function tslib_es6_metadata(metadataKey, metadataValue) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
}

function tslib_es6_awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

function tslib_es6_generator(thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
}

var tslib_es6_createBinding = Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
});

function tslib_es6_exportStar(m, o) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) tslib_es6_createBinding(o, m, p);
}

function tslib_es6_values(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}

function tslib_es6_read(o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
}

function tslib_es6_spread() {
    for (var ar = [], i = 0; i < arguments.length; i++)
        ar = ar.concat(tslib_es6_read(arguments[i]));
    return ar;
}

function tslib_es6_spreadArrays() {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};

function tslib_es6_await(v) {
    return this instanceof tslib_es6_await ? (this.v = v, this) : new tslib_es6_await(v);
}

function tslib_es6_asyncGenerator(thisArg, _arguments, generator) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var g = generator.apply(thisArg, _arguments || []), i, q = [];
    return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
    function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
    function step(r) { r.value instanceof tslib_es6_await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
    function fulfill(value) { resume("next", value); }
    function reject(value) { resume("throw", value); }
    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
}

function tslib_es6_asyncDelegator(o) {
    var i, p;
    return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
    function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: tslib_es6_await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
}

function tslib_es6_asyncValues(o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof tslib_es6_values === "function" ? tslib_es6_values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
}

function tslib_es6_makeTemplateObject(cooked, raw) {
    if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
    return cooked;
};

var tslib_es6_setModuleDefault = Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
};

function tslib_es6_importStar(mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) tslib_es6_createBinding(result, mod, k);
    tslib_es6_setModuleDefault(result, mod);
    return result;
}

function tslib_es6_importDefault(mod) {
    return (mod && mod.__esModule) ? mod : { default: mod };
}

function tslib_es6_classPrivateFieldGet(receiver, privateMap) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return privateMap.get(receiver);
}

function tslib_es6_classPrivateFieldSet(receiver, privateMap, value) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to set private field on non-instance");
    }
    privateMap.set(receiver, value);
    return value;
}

;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/clazz.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


var TYPE_DELIMITER = '.';
var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___';
/**
 * Notice, parseClassType('') should returns {main: '', sub: ''}
 * @public
 */

function parseClassType(componentType) {
  var ret = {
    main: '',
    sub: ''
  };

  if (componentType) {
    var typeArr = componentType.split(TYPE_DELIMITER);
    ret.main = typeArr[0] || '';
    ret.sub = typeArr[1] || '';
  }

  return ret;
}
/**
 * @public
 */

function checkClassType(componentType) {
  assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
}

function isExtendedClass(clz) {
  return !!(clz && clz[IS_EXTENDED_CLASS]);
}
/**
 * Implements `ExtendableConstructor` for `rootClz`.
 *
 * @usage
 * ```ts
 * class Xxx {}
 * type XxxConstructor = typeof Xxx & ExtendableConstructor
 * enableClassExtend(Xxx as XxxConstructor);
 * ```
 */

function enableClassExtend(rootClz, mandatoryMethods) {
  rootClz.$constructor = rootClz; // FIXME: not necessary?

  rootClz.extend = function (proto) {
    if (true) {
      each(mandatoryMethods, function (method) {
        if (!proto[method]) {
          console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.');
        }
      });
    }

    var superClass = this; // For backward compat, we both support ts class inheritance and this
    // "extend" approach.
    // The constructor should keep the same behavior as ts class inheritance:
    // If this constructor/$constructor is not declared, auto invoke the super
    // constructor.
    // If this constructor/$constructor is declared, it is responsible for
    // calling the super constructor.

    function ExtendedClass() {
      var args = [];

      for (var _i = 0; _i < arguments.length; _i++) {
        args[_i] = arguments[_i];
      }

      if (!proto.$constructor) {
        if (!isESClass(superClass)) {
          // Will throw error if superClass is an es6 native class.
          superClass.apply(this, arguments);
        } else {
          var ins = createObject( // @ts-ignore
          ExtendedClass.prototype, new (superClass.bind.apply(superClass, tslib_es6_spreadArrays([void 0], args)))());
          return ins;
        }
      } else {
        proto.$constructor.apply(this, arguments);
      }
    }

    ExtendedClass[IS_EXTENDED_CLASS] = true;
    util_extend(ExtendedClass.prototype, proto);
    ExtendedClass.extend = this.extend;
    ExtendedClass.superCall = superCall;
    ExtendedClass.superApply = superApply;
    inherits(ExtendedClass, this);
    ExtendedClass.superClass = superClass;
    return ExtendedClass;
  };
}

function isESClass(fn) {
  return typeof fn === 'function' && /^class\s/.test(Function.prototype.toString.call(fn));
}
/**
 * A work around to both support ts extend and this extend mechanism.
 * on sub-class.
 * @usage
 * ```ts
 * class Component { ... }
 * classUtil.enableClassExtend(Component);
 * classUtil.enableClassManagement(Component, {registerWhenExtend: true});
 *
 * class Series extends Component { ... }
 * // Without calling `markExtend`, `registerWhenExtend` will not work.
 * Component.markExtend(Series);
 * ```
 */


function mountExtend(SubClz, SupperClz) {
  SubClz.extend = SupperClz.extend;
} // A random offset.

var classBase = Math.round(Math.random() * 10);
/**
 * Implements `CheckableConstructor` for `target`.
 * Can not use instanceof, consider different scope by
 * cross domain or es module import in ec extensions.
 * Mount a method "isInstance()" to Clz.
 *
 * @usage
 * ```ts
 * class Xxx {}
 * type XxxConstructor = typeof Xxx & CheckableConstructor;
 * enableClassCheck(Xxx as XxxConstructor)
 * ```
 */

function enableClassCheck(target) {
  var classAttr = ['__\0is_clz', classBase++].join('_');
  target.prototype[classAttr] = true;

  if (true) {
    assert(!target.isInstance, 'The method "is" can not be defined.');
  }

  target.isInstance = function (obj) {
    return !!(obj && obj[classAttr]);
  };
} // superCall should have class info, which can not be fetch from 'this'.
// Consider this case:
// class A has method f,
// class B inherits class A, overrides method f, f call superApply('f'),
// class C inherits class B, do not overrides method f,
// then when method of class C is called, dead loop occured.

function superCall(context, methodName) {
  var args = [];

  for (var _i = 2; _i < arguments.length; _i++) {
    args[_i - 2] = arguments[_i];
  }

  return this.superClass.prototype[methodName].apply(context, args);
}

function superApply(context, methodName, args) {
  return this.superClass.prototype[methodName].apply(context, args);
}
/**
 * Implements `ClassManager` for `target`
 *
 * @usage
 * ```ts
 * class Xxx {}
 * type XxxConstructor = typeof Xxx & ClassManager
 * enableClassManagement(Xxx as XxxConstructor);
 * ```
 */


function enableClassManagement(target) {
  /**
   * Component model classes
   * key: componentType,
   * value:
   *     componentClass, when componentType is 'xxx'
   *     or Object.<subKey, componentClass>, when componentType is 'xxx.yy'
   */
  var storage = {};

  target.registerClass = function (clz) {
    // `type` should not be a "instance memeber".
    // If using TS class, should better declared as `static type = 'series.pie'`.
    // otherwise users have to mount `type` on prototype manually.
    // For backward compat and enable instance visit type via `this.type`,
    // we stil support fetch `type` from prototype.
    var componentFullType = clz.type || clz.prototype.type;

    if (componentFullType) {
      checkClassType(componentFullType); // If only static type declared, we assign it to prototype mandatorily.

      clz.prototype.type = componentFullType;
      var componentTypeInfo = parseClassType(componentFullType);

      if (!componentTypeInfo.sub) {
        if (true) {
          if (storage[componentTypeInfo.main]) {
            console.warn(componentTypeInfo.main + ' exists.');
          }
        }

        storage[componentTypeInfo.main] = clz;
      } else if (componentTypeInfo.sub !== IS_CONTAINER) {
        var container = makeContainer(componentTypeInfo);
        container[componentTypeInfo.sub] = clz;
      }
    }

    return clz;
  };

  target.getClass = function (mainType, subType, throwWhenNotFound) {
    var clz = storage[mainType];

    if (clz && clz[IS_CONTAINER]) {
      clz = subType ? clz[subType] : null;
    }

    if (throwWhenNotFound && !clz) {
      throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.');
    }

    return clz;
  };

  target.getClassesByMainType = function (componentType) {
    var componentTypeInfo = parseClassType(componentType);
    var result = [];
    var obj = storage[componentTypeInfo.main];

    if (obj && obj[IS_CONTAINER]) {
      each(obj, function (o, type) {
        type !== IS_CONTAINER && result.push(o);
      });
    } else {
      result.push(obj);
    }

    return result;
  };

  target.hasClass = function (componentType) {
    // Just consider componentType.main.
    var componentTypeInfo = parseClassType(componentType);
    return !!storage[componentTypeInfo.main];
  };
  /**
   * @return Like ['aa', 'bb'], but can not be ['aa.xx']
   */


  target.getAllClassMainTypes = function () {
    var types = [];
    each(storage, function (obj, type) {
      types.push(type);
    });
    return types;
  };
  /**
   * If a main type is container and has sub types
   */


  target.hasSubTypes = function (componentType) {
    var componentTypeInfo = parseClassType(componentType);
    var obj = storage[componentTypeInfo.main];
    return obj && obj[IS_CONTAINER];
  };

  function makeContainer(componentTypeInfo) {
    var container = storage[componentTypeInfo.main];

    if (!container || !container[IS_CONTAINER]) {
      container = storage[componentTypeInfo.main] = {};
      container[IS_CONTAINER] = true;
    }

    return container;
  }
} // /**
//  * @param {string|Array.<string>} properties
//  */
// export function setReadOnly(obj, properties) {
// FIXME It seems broken in IE8 simulation of IE11
// if (!zrUtil.isArray(properties)) {
//     properties = properties != null ? [properties] : [];
// }
// zrUtil.each(properties, function (prop) {
//     let value = obj[prop];
//     Object.defineProperty
//         && Object.defineProperty(obj, prop, {
//             value: value, writable: false
//         });
//     zrUtil.isArray(obj[prop])
//         && Object.freeze
//         && Object.freeze(obj[prop]);
// });
// }
;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/mixin/makeStyleMapper.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// TODO Parse shadow style
// TODO Only shallow path support

function makeStyleMapper(properties, ignoreParent) {
  // Normalize
  for (var i = 0; i < properties.length; i++) {
    if (!properties[i][1]) {
      properties[i][1] = properties[i][0];
    }
  }

  ignoreParent = ignoreParent || false;
  return function (model, excludes, includes) {
    var style = {};

    for (var i = 0; i < properties.length; i++) {
      var propName = properties[i][1];

      if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) {
        continue;
      }

      var val = model.getShallow(propName, ignoreParent);

      if (val != null) {
        style[properties[i][0]] = val;
      }
    } // TODO Text or image?


    return style;
  };
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/mixin/areaStyle.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
// So do not transfer decal directly.
];
var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP);

var AreaStyleMixin =
/** @class */
function () {
  function AreaStyleMixin() {}

  AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) {
    return getAreaStyle(this, excludes, includes);
  };

  return AreaStyleMixin;
}();

;

;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/mixin/textStyle.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


var PATH_COLOR = ['textStyle', 'color']; // TODO Performance improvement?

var tmpRichText = new Text();

var TextStyleMixin =
/** @class */
function () {
  function TextStyleMixin() {}
  /**
   * Get color property or get color from option.textStyle.color
   */
  // TODO Callback


  TextStyleMixin.prototype.getTextColor = function (isEmphasis) {
    var ecModel = this.ecModel;
    return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null);
  };
  /**
   * Create font string from fontStyle, fontWeight, fontSize, fontFamily
   * @return {string}
   */


  TextStyleMixin.prototype.getFont = function () {
    return getFont({
      fontStyle: this.getShallow('fontStyle'),
      fontWeight: this.getShallow('fontWeight'),
      fontSize: this.getShallow('fontSize'),
      fontFamily: this.getShallow('fontFamily')
    }, this.ecModel);
  };

  TextStyleMixin.prototype.getTextRect = function (text) {
    tmpRichText.useStyle({
      text: text,
      fontStyle: this.getShallow('fontStyle'),
      fontWeight: this.getShallow('fontWeight'),
      fontSize: this.getShallow('fontSize'),
      fontFamily: this.getShallow('fontFamily'),
      verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline'),
      padding: this.getShallow('padding'),
      lineHeight: this.getShallow('lineHeight'),
      rich: this.getShallow('rich')
    });
    tmpRichText.update();
    return tmpRichText.getBoundingRect();
  };

  return TextStyleMixin;
}();

;
/* harmony default export */ const textStyle = (TextStyleMixin);
;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/mixin/lineStyle.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'type'], ['lineDashOffset', 'dashOffset'], ['lineCap', 'cap'], ['lineJoin', 'join'], ['miterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
// So do not transfer decal directly.
];
var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP);

var LineStyleMixin =
/** @class */
function () {
  function LineStyleMixin() {}

  LineStyleMixin.prototype.getLineStyle = function (excludes) {
    return getLineStyle(this, excludes);
  };

  return LineStyleMixin;
}();

;

;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/mixin/itemStyle.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

var ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'borderType'], ['lineDashOffset', 'borderDashOffset'], ['lineCap', 'borderCap'], ['lineJoin', 'borderJoin'], ['miterLimit', 'borderMiterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
// So do not transfer decal directly.
];
var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP);

var ItemStyleMixin =
/** @class */
function () {
  function ItemStyleMixin() {}

  ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) {
    return getItemStyle(this, excludes, includes);
  };

  return ItemStyleMixin;
}();


;// CONCATENATED MODULE: ./node_modules/echarts/lib/model/Model.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/








var Model =
/** @class */
function () {
  function Model(option, parentModel, ecModel) {
    this.parentModel = parentModel;
    this.ecModel = ecModel;
    this.option = option; // Simple optimization
    // if (this.init) {
    //     if (arguments.length <= 4) {
    //         this.init(option, parentModel, ecModel, extraOpt);
    //     }
    //     else {
    //         this.init.apply(this, arguments);
    //     }
    // }
  }

  Model.prototype.init = function (option, parentModel, ecModel) {
    var rest = [];

    for (var _i = 3; _i < arguments.length; _i++) {
      rest[_i - 3] = arguments[_i];
    }
  };
  /**
   * Merge the input option to me.
   */


  Model.prototype.mergeOption = function (option, ecModel) {
    merge(this.option, option, true);
  }; // `path` can be 'xxx.yyy.zzz', so the return value type have to be `ModelOption`
  // TODO: TYPE strict key check?
  // get(path: string | string[], ignoreParent?: boolean): ModelOption;


  Model.prototype.get = function (path, ignoreParent) {
    if (path == null) {
      return this.option;
    }

    return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel);
  };

  Model.prototype.getShallow = function (key, ignoreParent) {
    var option = this.option;
    var val = option == null ? option : option[key];

    if (val == null && !ignoreParent) {
      var parentModel = this.parentModel;

      if (parentModel) {
        // FIXME:TS do not know how to make it works
        val = parentModel.getShallow(key);
      }
    }

    return val;
  }; // `path` can be 'xxx.yyy.zzz', so the return value type have to be `Model<ModelOption>`
  // getModel(path: string | string[], parentModel?: Model): Model;
  // TODO 'xxx.yyy.zzz' is deprecated


  Model.prototype.getModel = function (path, parentModel) {
    var hasPath = path != null;
    var pathFinal = hasPath ? this.parsePath(path) : null;
    var obj = hasPath ? this._doGet(pathFinal) : this.option;
    parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal));
    return new Model(obj, parentModel, this.ecModel);
  };
  /**
   * Squash option stack into one.
   * parentModel will be removed after squashed.
   *
   * NOTE: resolveParentPath will not be applied here for simplicity. DON'T use this function
   * if resolveParentPath is modified.
   *
   * @param deepMerge If do deep merge. Default to be false.
   */
  // squash(
  //     deepMerge?: boolean,
  //     handleCallback?: (func: () => object) => object
  // ) {
  //     const optionStack = [];
  //     let model: Model = this;
  //     while (model) {
  //         if (model.option) {
  //             optionStack.push(model.option);
  //         }
  //         model = model.parentModel;
  //     }
  //     const newOption = {} as Opt;
  //     let option;
  //     while (option = optionStack.pop()) {    // Top down merge
  //         if (isFunction(option) && handleCallback) {
  //             option = handleCallback(option);
  //         }
  //         if (deepMerge) {
  //             merge(newOption, option);
  //         }
  //         else {
  //             extend(newOption, option);
  //         }
  //     }
  //     // Remove parentModel
  //     this.option = newOption;
  //     this.parentModel = null;
  // }

  /**
   * If model has option
   */


  Model.prototype.isEmpty = function () {
    return this.option == null;
  };

  Model.prototype.restoreData = function () {}; // Pending


  Model.prototype.clone = function () {
    var Ctor = this.constructor;
    return new Ctor(clone(this.option));
  }; // setReadOnly(properties): void {
  // clazzUtil.setReadOnly(this, properties);
  // }
  // If path is null/undefined, return null/undefined.


  Model.prototype.parsePath = function (path) {
    if (typeof path === 'string') {
      return path.split('.');
    }

    return path;
  }; // Resolve path for parent. Perhaps useful when parent use a different property.
  // Default to be a identity resolver.
  // Can be modified to a different resolver.


  Model.prototype.resolveParentPath = function (path) {
    return path;
  }; // FIXME:TS check whether put this method here


  Model.prototype.isAnimationEnabled = function () {
    if (!core_env.node && this.option) {
      if (this.option.animation != null) {
        return !!this.option.animation;
      } else if (this.parentModel) {
        return this.parentModel.isAnimationEnabled();
      }
    }
  };

  Model.prototype._doGet = function (pathArr, parentModel) {
    var obj = this.option;

    if (!pathArr) {
      return obj;
    }

    for (var i = 0; i < pathArr.length; i++) {
      // Ignore empty
      if (!pathArr[i]) {
        continue;
      } // obj could be number/string/... (like 0)


      obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null;

      if (obj == null) {
        break;
      }
    }

    if (obj == null && parentModel) {
      obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel);
    }

    return obj;
  };

  return Model;
}();

; // Enable Model.extend.

enableClassExtend(Model);
enableClassCheck(Model);
mixin(Model, LineStyleMixin);
mixin(Model, ItemStyleMixin);
mixin(Model, AreaStyleMixin);
mixin(Model, textStyle);
/* harmony default export */ const model_Model = (Model);
;// CONCATENATED MODULE: ./node_modules/echarts/lib/i18n/langEN.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
 * Language: English.
 */
/* harmony default export */ const langEN = ({
  time: {
    month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
    monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
    dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
    dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
  },
  legend: {
    selector: {
      all: 'All',
      inverse: 'Inv'
    }
  },
  toolbox: {
    brush: {
      title: {
        rect: 'Box Select',
        polygon: 'Lasso Select',
        lineX: 'Horizontally Select',
        lineY: 'Vertically Select',
        keep: 'Keep Selections',
        clear: 'Clear Selections'
      }
    },
    dataView: {
      title: 'Data View',
      lang: ['Data View', 'Close', 'Refresh']
    },
    dataZoom: {
      title: {
        zoom: 'Zoom',
        back: 'Zoom Reset'
      }
    },
    magicType: {
      title: {
        line: 'Switch to Line Chart',
        bar: 'Switch to Bar Chart',
        stack: 'Stack',
        tiled: 'Tile'
      }
    },
    restore: {
      title: 'Restore'
    },
    saveAsImage: {
      title: 'Save as Image',
      lang: ['Right Click to Save Image']
    }
  },
  series: {
    typeNames: {
      pie: 'Pie chart',
      bar: 'Bar chart',
      line: 'Line chart',
      scatter: 'Scatter plot',
      effectScatter: 'Ripple scatter plot',
      radar: 'Radar chart',
      tree: 'Tree',
      treemap: 'Treemap',
      boxplot: 'Boxplot',
      candlestick: 'Candlestick',
      k: 'K line chart',
      heatmap: 'Heat map',
      map: 'Map',
      parallel: 'Parallel coordinate map',
      lines: 'Line graph',
      graph: 'Relationship graph',
      sankey: 'Sankey diagram',
      funnel: 'Funnel chart',
      gauge: 'Gauge',
      pictorialBar: 'Pictorial bar',
      themeRiver: 'Theme River Map',
      sunburst: 'Sunburst'
    }
  },
  aria: {
    general: {
      withTitle: 'This is a chart about "{title}"',
      withoutTitle: 'This is a chart'
    },
    series: {
      single: {
        prefix: '',
        withName: ' with type {seriesType} named {seriesName}.',
        withoutName: ' with type {seriesType}.'
      },
      multiple: {
        prefix: '. It consists of {seriesCount} series count.',
        withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.',
        withoutName: ' The {seriesId} series is a {seriesType}.',
        separator: {
          middle: '',
          end: ''
        }
      }
    },
    data: {
      allData: 'The data is as follows: ',
      partialData: 'The first {displayCnt} items are: ',
      withName: 'the data for {name} is {value}',
      withoutName: '{value}',
      separator: {
        middle: ', ',
        end: '. '
      }
    }
  }
});
;// CONCATENATED MODULE: ./node_modules/echarts/lib/i18n/langZH.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
/* harmony default export */ const langZH = ({
  time: {
    month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
    monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
    dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
    dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六']
  },
  legend: {
    selector: {
      all: '全选',
      inverse: '反选'
    }
  },
  toolbox: {
    brush: {
      title: {
        rect: '矩形选择',
        polygon: '圈选',
        lineX: '横向选择',
        lineY: '纵向选择',
        keep: '保持选择',
        clear: '清除选择'
      }
    },
    dataView: {
      title: '数据视图',
      lang: ['数据视图', '关闭', '刷新']
    },
    dataZoom: {
      title: {
        zoom: '区域缩放',
        back: '区域缩放还原'
      }
    },
    magicType: {
      title: {
        line: '切换为折线图',
        bar: '切换为柱状图',
        stack: '切换为堆叠',
        tiled: '切换为平铺'
      }
    },
    restore: {
      title: '还原'
    },
    saveAsImage: {
      title: '保存为图片',
      lang: ['右键另存为图片']
    }
  },
  series: {
    typeNames: {
      pie: '饼图',
      bar: '柱状图',
      line: '折线图',
      scatter: '散点图',
      effectScatter: '涟漪散点图',
      radar: '雷达图',
      tree: '树图',
      treemap: '矩形树图',
      boxplot: '箱型图',
      candlestick: 'K线图',
      k: 'K线图',
      heatmap: '热力图',
      map: '地图',
      parallel: '平行坐标图',
      lines: '线图',
      graph: '关系图',
      sankey: '桑基图',
      funnel: '漏斗图',
      gauge: '仪表盘图',
      pictorialBar: '象形柱图',
      themeRiver: '主题河流图',
      sunburst: '旭日图'
    }
  },
  aria: {
    general: {
      withTitle: '这是一个关于“{title}”的图表。',
      withoutTitle: '这是一个图表，'
    },
    series: {
      single: {
        prefix: '',
        withName: '图表类型是{seriesType}，表示{seriesName}。',
        withoutName: '图表类型是{seriesType}。'
      },
      multiple: {
        prefix: '它由{seriesCount}个图表系列组成。',
        withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType}，',
        withoutName: '第{seriesId}个系列是一个{seriesType}，',
        separator: {
          middle: '；',
          end: '。'
        }
      }
    },
    data: {
      allData: '其数据是——',
      partialData: '其中，前{displayCnt}项是——',
      withName: '{name}的数据是{value}',
      withoutName: '{value}',
      separator: {
        middle: '，',
        end: ''
      }
    }
  }
});
;// CONCATENATED MODULE: ./node_modules/echarts/lib/core/locale.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

 // default import ZH and EN lang




var LOCALE_ZH = 'ZH';
var LOCALE_EN = 'EN';
var DEFAULT_LOCALE = LOCALE_EN;
var localeStorage = {};
var localeModels = {};
var SYSTEM_LANG = !core_env.domSupported ? DEFAULT_LOCALE : function () {
  var langStr = (
  /* eslint-disable-next-line */
  document.documentElement.lang || navigator.language || navigator.browserLanguage).toUpperCase();
  return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE;
}();
function registerLocale(locale, localeObj) {
  locale = locale.toUpperCase();
  localeModels[locale] = new model_Model(localeObj);
  localeStorage[locale] = localeObj;
} // export function getLocale(locale: string) {
//     return localeStorage[locale];
// }

function createLocaleObject(locale) {
  if (isString(locale)) {
    var localeObj = localeStorage[locale.toUpperCase()] || {};

    if (locale === LOCALE_ZH || locale === LOCALE_EN) {
      return clone(localeObj);
    } else {
      return merge(clone(localeObj), clone(localeStorage[DEFAULT_LOCALE]), false);
    }
  } else {
    return merge(clone(locale), clone(localeStorage[DEFAULT_LOCALE]), false);
  }
}
function getLocaleModel(lang) {
  return localeModels[lang];
}
function getDefaultLocaleModel() {
  return localeModels[DEFAULT_LOCALE];
} // Default locale

registerLocale(LOCALE_EN, langEN);
registerLocale(LOCALE_ZH, langZH);
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/time.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/




var ONE_SECOND = 1000;
var ONE_MINUTE = ONE_SECOND * 60;
var ONE_HOUR = ONE_MINUTE * 60;
var ONE_DAY = ONE_HOUR * 24;
var ONE_YEAR = ONE_DAY * 365;
var defaultLeveledFormatter = {
  year: '{yyyy}',
  month: '{MMM}',
  day: '{d}',
  hour: '{HH}:{mm}',
  minute: '{HH}:{mm}',
  second: '{HH}:{mm}:{ss}',
  millisecond: '{hh}:{mm}:{ss} {SSS}',
  none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss} {SSS}'
};
var fullDayFormatter = '{yyyy}-{MM}-{dd}';
var fullLeveledFormatter = {
  year: '{yyyy}',
  month: '{yyyy}-{MM}',
  day: fullDayFormatter,
  hour: fullDayFormatter + ' ' + defaultLeveledFormatter.hour,
  minute: fullDayFormatter + ' ' + defaultLeveledFormatter.minute,
  second: fullDayFormatter + ' ' + defaultLeveledFormatter.second,
  millisecond: defaultLeveledFormatter.none
};
var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];
var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond'];
function pad(str, len) {
  str += '';
  return '0000'.substr(0, len - str.length) + str;
}
function getPrimaryTimeUnit(timeUnit) {
  switch (timeUnit) {
    case 'half-year':
    case 'quarter':
      return 'month';

    case 'week':
    case 'half-week':
      return 'day';

    case 'half-day':
    case 'quarter-day':
      return 'hour';

    default:
      // year, minutes, second, milliseconds
      return timeUnit;
  }
}
function isPrimaryTimeUnit(timeUnit) {
  return timeUnit === getPrimaryTimeUnit(timeUnit);
}
function getDefaultFormatPrecisionOfInterval(timeUnit) {
  switch (timeUnit) {
    case 'year':
    case 'month':
      return 'day';

    case 'millisecond':
      return 'millisecond';

    default:
      // Also for day, hour, minute, second
      return 'second';
  }
}
function format( // Note: The result based on `isUTC` are totally different, which can not be just simply
// substituted by the result without `isUTC`. So we make the param `isUTC` mandatory.
time, template, isUTC, lang) {
  var date = parseDate(time);
  var y = date[fullYearGetterName(isUTC)]();
  var M = date[monthGetterName(isUTC)]() + 1;
  var q = Math.floor((M - 1) / 4) + 1;
  var d = date[dateGetterName(isUTC)]();
  var e = date['get' + (isUTC ? 'UTC' : '') + 'Day']();
  var H = date[hoursGetterName(isUTC)]();
  var h = (H - 1) % 12 + 1;
  var m = date[minutesGetterName(isUTC)]();
  var s = date[secondsGetterName(isUTC)]();
  var S = date[millisecondsGetterName(isUTC)]();
  var localeModel = lang instanceof model_Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel();
  var timeModel = localeModel.getModel('time');
  var month = timeModel.get('month');
  var monthAbbr = timeModel.get('monthAbbr');
  var dayOfWeek = timeModel.get('dayOfWeek');
  var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr');
  return (template || '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, y % 100 + '').replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + '');
}
function leveledFormat(tick, idx, formatter, lang, isUTC) {
  var template = null;

  if (typeof formatter === 'string') {
    // Single formatter for all units at all levels
    template = formatter;
  } else if (typeof formatter === 'function') {
    // Callback formatter
    template = formatter(tick.value, idx, {
      level: tick.level
    });
  } else {
    var defaults = util_extend({}, defaultLeveledFormatter);

    if (tick.level > 0) {
      for (var i = 0; i < primaryTimeUnits.length; ++i) {
        defaults[primaryTimeUnits[i]] = "{primary|" + defaults[primaryTimeUnits[i]] + "}";
      }
    }

    var mergedFormatter = formatter ? formatter.inherit === false ? formatter // Use formatter with bigger units
    : util_defaults(formatter, defaults) : defaults;
    var unit = getUnitFromValue(tick.value, isUTC);

    if (mergedFormatter[unit]) {
      template = mergedFormatter[unit];
    } else if (mergedFormatter.inherit) {
      // Unit formatter is not defined and should inherit from bigger units
      var targetId = timeUnits.indexOf(unit);

      for (var i = targetId - 1; i >= 0; --i) {
        if (mergedFormatter[unit]) {
          template = mergedFormatter[unit];
          break;
        }
      }

      template = template || defaults.none;
    }

    if (isArray(template)) {
      var levelId = tick.level == null ? 0 : tick.level >= 0 ? tick.level : template.length + tick.level;
      levelId = Math.min(levelId, template.length - 1);
      template = template[levelId];
    }
  }

  return format(new Date(tick.value), template, isUTC, lang);
}
function getUnitFromValue(value, isUTC) {
  var date = parseDate(value);
  var M = date[monthGetterName(isUTC)]() + 1;
  var d = date[dateGetterName(isUTC)]();
  var h = date[hoursGetterName(isUTC)]();
  var m = date[minutesGetterName(isUTC)]();
  var s = date[secondsGetterName(isUTC)]();
  var S = date[millisecondsGetterName(isUTC)]();
  var isSecond = S === 0;
  var isMinute = isSecond && s === 0;
  var isHour = isMinute && m === 0;
  var isDay = isHour && h === 0;
  var isMonth = isDay && d === 1;
  var isYear = isMonth && M === 1;

  if (isYear) {
    return 'year';
  } else if (isMonth) {
    return 'month';
  } else if (isDay) {
    return 'day';
  } else if (isHour) {
    return 'hour';
  } else if (isMinute) {
    return 'minute';
  } else if (isSecond) {
    return 'second';
  } else {
    return 'millisecond';
  }
}
function getUnitValue(value, unit, isUTC) {
  var date = typeof value === 'number' ? parseDate(value) : value;
  unit = unit || getUnitFromValue(value, isUTC);

  switch (unit) {
    case 'year':
      return date[fullYearGetterName(isUTC)]();

    case 'half-year':
      return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;

    case 'quarter':
      return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);

    case 'month':
      return date[monthGetterName(isUTC)]();

    case 'day':
      return date[dateGetterName(isUTC)]();

    case 'half-day':
      return date[hoursGetterName(isUTC)]() / 24;

    case 'hour':
      return date[hoursGetterName(isUTC)]();

    case 'minute':
      return date[minutesGetterName(isUTC)]();

    case 'second':
      return date[secondsGetterName(isUTC)]();

    case 'millisecond':
      return date[millisecondsGetterName(isUTC)]();
  }
}
function fullYearGetterName(isUTC) {
  return isUTC ? 'getUTCFullYear' : 'getFullYear';
}
function monthGetterName(isUTC) {
  return isUTC ? 'getUTCMonth' : 'getMonth';
}
function dateGetterName(isUTC) {
  return isUTC ? 'getUTCDate' : 'getDate';
}
function hoursGetterName(isUTC) {
  return isUTC ? 'getUTCHours' : 'getHours';
}
function minutesGetterName(isUTC) {
  return isUTC ? 'getUTCMinutes' : 'getMinutes';
}
function secondsGetterName(isUTC) {
  return isUTC ? 'getUTCSeconds' : 'getSeconds';
}
function millisecondsGetterName(isUTC) {
  return isUTC ? 'getUTCSeconds' : 'getSeconds';
}
function fullYearSetterName(isUTC) {
  return isUTC ? 'setUTCFullYear' : 'setFullYear';
}
function monthSetterName(isUTC) {
  return isUTC ? 'setUTCMonth' : 'setMonth';
}
function dateSetterName(isUTC) {
  return isUTC ? 'setUTCDate' : 'setDate';
}
function hoursSetterName(isUTC) {
  return isUTC ? 'setUTCHours' : 'setHours';
}
function minutesSetterName(isUTC) {
  return isUTC ? 'setUTCMinutes' : 'setMinutes';
}
function secondsSetterName(isUTC) {
  return isUTC ? 'setUTCSeconds' : 'setSeconds';
}
function millisecondsSetterName(isUTC) {
  return isUTC ? 'setUTCSeconds' : 'setSeconds';
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/legacy/getTextRect.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


function getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) {
  deprecateLog('getTextRect is deprecated.');
  var textEl = new Text({
    style: {
      text: text,
      font: font,
      align: align,
      verticalAlign: verticalAlign,
      padding: padding,
      rich: rich,
      overflow: truncate ? 'truncate' : null,
      lineHeight: lineHeight
    }
  });
  return textEl.getBoundingRect();
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/format.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/




/**
 * Add a comma each three digit.
 */

function addCommas(x) {
  if (!isNumeric(x)) {
    return isString(x) ? x : '-';
  }

  var parts = (x + '').split('.');
  return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : '');
}
function toCamelCase(str, upperCaseFirst) {
  str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {
    return group1.toUpperCase();
  });

  if (upperCaseFirst && str) {
    str = str.charAt(0).toUpperCase() + str.slice(1);
  }

  return str;
}
var format_normalizeCssArray = normalizeCssArray;
var replaceReg = /([&<>"'])/g;
var replaceMap = {
  '&': '&amp;',
  '<': '&lt;',
  '>': '&gt;',
  '"': '&quot;',
  '\'': '&#39;'
};
function encodeHTML(source) {
  return source == null ? '' : (source + '').replace(replaceReg, function (str, c) {
    return replaceMap[c];
  });
}
/**
 * Make value user readable for tooltip and label.
 * "User readable":
 *     Try to not print programmer-specific text like NaN, Infinity, null, undefined.
 *     Avoid to display an empty string, which users can not recognize there is
 *     a value and it might look like a bug.
 */

function makeValueReadable(value, valueType, useUTC) {
  var USER_READABLE_DEFUALT_TIME_PATTERN = '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss}';

  function stringToUserReadable(str) {
    return str && trim(str) ? str : '-';
  }

  function isNumberUserReadable(num) {
    return !!(num != null && !isNaN(num) && isFinite(num));
  }

  var isTypeTime = valueType === 'time';
  var isValueDate = value instanceof Date;

  if (isTypeTime || isValueDate) {
    var date = isTypeTime ? parseDate(value) : value;

    if (!isNaN(+date)) {
      return format(date, USER_READABLE_DEFUALT_TIME_PATTERN, useUTC);
    } else if (isValueDate) {
      return '-';
    } // In other cases, continue to try to display the value in the following code.

  }

  if (valueType === 'ordinal') {
    return isStringSafe(value) ? stringToUserReadable(value) : isNumber(value) ? isNumberUserReadable(value) ? value + '' : '-' : '-';
  } // By default.


  var numericResult = numericToNumber(value);
  return isNumberUserReadable(numericResult) ? addCommas(numericResult) : isStringSafe(value) ? stringToUserReadable(value) : '-';
}
var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

var wrapVar = function (varName, seriesIdx) {
  return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';
};
/**
 * Template formatter
 * @param {Array.<Object>|Object} paramsList
 */


function formatTpl(tpl, paramsList, encode) {
  if (!isArray(paramsList)) {
    paramsList = [paramsList];
  }

  var seriesLen = paramsList.length;

  if (!seriesLen) {
    return '';
  }

  var $vars = paramsList[0].$vars || [];

  for (var i = 0; i < $vars.length; i++) {
    var alias = TPL_VAR_ALIAS[i];
    tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));
  }

  for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {
    for (var k = 0; k < $vars.length; k++) {
      var val = paramsList[seriesIdx][$vars[k]];
      tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val);
    }
  }

  return tpl;
}
/**
 * simple Template formatter
 */

function formatTplSimple(tpl, param, encode) {
  each(param, function (value, key) {
    tpl = tpl.replace('{' + key + '}', encode ? encodeHTML(value) : value);
  });
  return tpl;
}
function getTooltipMarker(inOpt, extraCssText) {
  var opt = isString(inOpt) ? {
    color: inOpt,
    extraCssText: extraCssText
  } : inOpt || {};
  var color = opt.color;
  var type = opt.type;
  extraCssText = opt.extraCssText;
  var renderMode = opt.renderMode || 'html';

  if (!color) {
    return '';
  }

  if (renderMode === 'html') {
    return type === 'subItem' ? '<span style="display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;' + 'border-radius:4px;width:4px;height:4px;background-color:' // Only support string
    + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>' : '<span style="display:inline-block;margin-right:4px;' + 'border-radius:10px;width:10px;height:10px;background-color:' + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>';
  } else {
    // Should better not to auto generate style name by auto-increment number here.
    // Because this util is usually called in tooltip formatter, which is probably
    // called repeatly when mouse move and the auto-increment number increases fast.
    // Users can make their own style name by theirselves, make it unique and readable.
    var markerId = opt.markerId || 'markerX';
    return {
      renderMode: renderMode,
      content: '{' + markerId + '|}  ',
      style: type === 'subItem' ? {
        width: 4,
        height: 4,
        borderRadius: 2,
        backgroundColor: color
      } : {
        width: 10,
        height: 10,
        borderRadius: 5,
        backgroundColor: color
      }
    };
  }
}
/**
 * @deprecated Use `time/format` instead.
 * ISO Date format
 * @param {string} tpl
 * @param {number} value
 * @param {boolean} [isUTC=false] Default in local time.
 *           see `module:echarts/scale/Time`
 *           and `module:echarts/util/number#parseDate`.
 * @inner
 */

function formatTime(tpl, value, isUTC) {
  if (true) {
    deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format');
  }

  if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') {
    tpl = 'MM-dd\nyyyy';
  }

  var date = parseDate(value);
  var utc = isUTC ? 'UTC' : '';
  var y = date['get' + utc + 'FullYear']();
  var M = date['get' + utc + 'Month']() + 1;
  var d = date['get' + utc + 'Date']();
  var h = date['get' + utc + 'Hours']();
  var m = date['get' + utc + 'Minutes']();
  var s = date['get' + utc + 'Seconds']();
  var S = date['get' + utc + 'Milliseconds']();
  tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', y % 100 + '').replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3));
  return tpl;
}
/**
 * Capital first
 * @param {string} str
 * @return {string}
 */

function capitalFirst(str) {
  return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;
}
/**
 * @return Never be null/undefined.
 */

function convertToColorString(color, defaultColor) {
  defaultColor = defaultColor || 'transparent';
  return isString(color) ? color : isObject(color) ? color.colorStops && (color.colorStops[0] || {}).color || defaultColor : defaultColor;
}

/**
 * open new tab
 * @param link url
 * @param target blank or self
 */

function windowOpen(link, target) {
  /* global window */
  if (target === '_blank' || target === 'blank') {
    var blank = window.open();
    blank.opener = null;
    blank.location.href = link;
  } else {
    window.open(link, target);
  }
}

;// CONCATENATED MODULE: ./node_modules/echarts/lib/util/layout.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
// Layout helpers for each component positioning




var layout_each = each;
/**
 * @public
 */

var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height'];
/**
 * @public
 */

var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']];

function boxLayout(orient, group, gap, maxWidth, maxHeight) {
  var x = 0;
  var y = 0;

  if (maxWidth == null) {
    maxWidth = Infinity;
  }

  if (maxHeight == null) {
    maxHeight = Infinity;
  }

  var currentLineMaxSize = 0;
  group.eachChild(function (child, idx) {
    var rect = child.getBoundingRect();
    var nextChild = group.childAt(idx + 1);
    var nextChildRect = nextChild && nextChild.getBoundingRect();
    var nextX;
    var nextY;

    if (orient === 'horizontal') {
      var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0);
      nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group
      // FIXME compare before adding gap?

      if (nextX > maxWidth || child.newline) {
        x = 0;
        nextX = moveX;
        y += currentLineMaxSize + gap;
        currentLineMaxSize = rect.height;
      } else {
        // FIXME: consider rect.y is not `0`?
        currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
      }
    } else {
      var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0);
      nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group

      if (nextY > maxHeight || child.newline) {
        x += currentLineMaxSize + gap;
        y = 0;
        nextY = moveY;
        currentLineMaxSize = rect.width;
      } else {
        currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
      }
    }

    if (child.newline) {
      return;
    }

    child.x = x;
    child.y = y;
    child.markRedraw();
    orient === 'horizontal' ? x = nextX + gap : y = nextY + gap;
  });
}
/**
 * VBox or HBox layouting
 * @param {string} orient
 * @param {module:zrender/graphic/Group} group
 * @param {number} gap
 * @param {number} [width=Infinity]
 * @param {number} [height=Infinity]
 */


var box = boxLayout;
/**
 * VBox layouting
 * @param {module:zrender/graphic/Group} group
 * @param {number} gap
 * @param {number} [width=Infinity]
 * @param {number} [height=Infinity]
 */

var vbox = curry(boxLayout, 'vertical');
/**
 * HBox layouting
 * @param {module:zrender/graphic/Group} group
 * @param {number} gap
 * @param {number} [width=Infinity]
 * @param {number} [height=Infinity]
 */

var hbox = curry(boxLayout, 'horizontal');
/**
 * If x or x2 is not specified or 'center' 'left' 'right',
 * the width would be as long as possible.
 * If y or y2 is not specified or 'middle' 'top' 'bottom',
 * the height would be as long as possible.
 */

function getAvailableSize(positionInfo, containerRect, margin) {
  var containerWidth = containerRect.width;
  var containerHeight = containerRect.height;
  var x = number_parsePercent(positionInfo.left, containerWidth);
  var y = number_parsePercent(positionInfo.top, containerHeight);
  var x2 = number_parsePercent(positionInfo.right, containerWidth);
  var y2 = number_parsePercent(positionInfo.bottom, containerHeight);
  (isNaN(x) || isNaN(parseFloat(positionInfo.left))) && (x = 0);
  (isNaN(x2) || isNaN(parseFloat(positionInfo.right))) && (x2 = containerWidth);
  (isNaN(y) || isNaN(parseFloat(positionInfo.top))) && (y = 0);
  (isNaN(y2) || isNaN(parseFloat(positionInfo.bottom))) && (y2 = containerHeight);
  margin = format_normalizeCssArray(margin || 0);
  return {
    width: Math.max(x2 - x - margin[1] - margin[3], 0),
    height: Math.max(y2 - y - margin[0] - margin[2], 0)
  };
}
/**
 * Parse position info.
 */

function getLayoutRect(positionInfo, containerRect, margin) {
  margin = format_normalizeCssArray(margin || 0);
  var containerWidth = containerRect.width;
  var containerHeight = containerRect.height;
  var left = number_parsePercent(positionInfo.left, containerWidth);
  var top = number_parsePercent(positionInfo.top, containerHeight);
  var right = number_parsePercent(positionInfo.right, containerWidth);
  var bottom = number_parsePercent(positionInfo.bottom, containerHeight);
  var width = number_parsePercent(positionInfo.width, containerWidth);
  var height = number_parsePercent(positionInfo.height, containerHeight);
  var verticalMargin = margin[2] + margin[0];
  var horizontalMargin = margin[1] + margin[3];
  var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right

  if (isNaN(width)) {
    width = containerWidth - right - horizontalMargin - left;
  }

  if (isNaN(height)) {
    height = containerHeight - bottom - verticalMargin - top;
  }

  if (aspect != null) {
    // If width and height are not given
    // 1. Graph should not exceeds the container
    // 2. Aspect must be keeped
    // 3. Graph should take the space as more as possible
    // FIXME
    // Margin is not considered, because there is no case that both
    // using margin and aspect so far.
    if (isNaN(width) && isNaN(height)) {
      if (aspect > containerWidth / containerHeight) {
        width = containerWidth * 0.8;
      } else {
        height = containerHeight * 0.8;
      }
    } // Calculate width or height with given aspect


    if (isNaN(width)) {
      width = aspect * height;
    }

    if (isNaN(height)) {
      height = width / aspect;
    }
  } // If left is not specified, calculate left from right and width


  if (isNaN(left)) {
    left = containerWidth - right - width - horizontalMargin;
  }

  if (isNaN(top)) {
    top = containerHeight - bottom - height - verticalMargin;
  } // Align left and top


  switch (positionInfo.left || positionInfo.right) {
    case 'center':
      left = containerWidth / 2 - width / 2 - margin[3];
      break;

    case 'right':
      left = containerWidth - width - horizontalMargin;
      break;
  }

  switch (positionInfo.top || positionInfo.bottom) {
    case 'middle':
    case 'center':
      top = containerHeight / 2 - height / 2 - margin[0];
      break;

    case 'bottom':
      top = containerHeight - height - verticalMargin;
      break;
  } // If something is wrong and left, top, width, height are calculated as NaN


  left = left || 0;
  top = top || 0;

  if (isNaN(width)) {
    // Width may be NaN if only one value is given except width
    width = containerWidth - horizontalMargin - left - (right || 0);
  }

  if (isNaN(height)) {
    // Height may be NaN if only one value is given except height
    height = containerHeight - verticalMargin - top - (bottom || 0);
  }

  var rect = new core_BoundingRect(left + margin[3], top + margin[0], width, height);
  rect.margin = margin;
  return rect;
}
/**
 * Position a zr element in viewport
 *  Group position is specified by either
 *  {left, top}, {right, bottom}
 *  If all properties exists, right and bottom will be igonred.
 *
 * Logic:
 *     1. Scale (against origin point in parent coord)
 *     2. Rotate (against origin point in parent coord)
 *     3. Traslate (with el.position by this method)
 * So this method only fixes the last step 'Traslate', which does not affect
 * scaling and rotating.
 *
 * If be called repeatly with the same input el, the same result will be gotten.
 *
 * @param el Should have `getBoundingRect` method.
 * @param positionInfo
 * @param positionInfo.left
 * @param positionInfo.top
 * @param positionInfo.right
 * @param positionInfo.bottom
 * @param positionInfo.width Only for opt.boundingModel: 'raw'
 * @param positionInfo.height Only for opt.boundingModel: 'raw'
 * @param containerRect
 * @param margin
 * @param opt
 * @param opt.hv Only horizontal or only vertical. Default to be [1, 1]
 * @param opt.boundingMode
 *        Specify how to calculate boundingRect when locating.
 *        'all': Position the boundingRect that is transformed and uioned
 *               both itself and its descendants.
 *               This mode simplies confine the elements in the bounding
 *               of their container (e.g., using 'right: 0').
 *        'raw': Position the boundingRect that is not transformed and only itself.
 *               This mode is useful when you want a element can overflow its
 *               container. (Consider a rotated circle needs to be located in a corner.)
 *               In this mode positionInfo.width/height can only be number.
 */

function positionElement(el, positionInfo, containerRect, margin, opt) {
  var h = !opt || !opt.hv || opt.hv[0];
  var v = !opt || !opt.hv || opt.hv[1];
  var boundingMode = opt && opt.boundingMode || 'all';

  if (!h && !v) {
    return;
  }

  var rect;

  if (boundingMode === 'raw') {
    rect = el.type === 'group' ? new core_BoundingRect(0, 0, +positionInfo.width || 0, +positionInfo.height || 0) : el.getBoundingRect();
  } else {
    rect = el.getBoundingRect();

    if (el.needLocalTransform()) {
      var transform = el.getLocalTransform(); // Notice: raw rect may be inner object of el,
      // which should not be modified.

      rect = rect.clone();
      rect.applyTransform(transform);
    }
  } // The real width and height can not be specified but calculated by the given el.


  var layoutRect = getLayoutRect(util_defaults({
    width: rect.width,
    height: rect.height
  }, positionInfo), containerRect, margin); // Because 'tranlate' is the last step in transform
  // (see zrender/core/Transformable#getLocalTransform),
  // we can just only modify el.position to get final result.

  var dx = h ? layoutRect.x - rect.x : 0;
  var dy = v ? layoutRect.y - rect.y : 0;

  if (boundingMode === 'raw') {
    el.x = dx;
    el.y = dy;
  } else {
    el.x += dx;
    el.y += dy;
  }

  el.markRedraw();
}
/**
 * @param option Contains some of the properties in HV_NAMES.
 * @param hvIdx 0: horizontal; 1: vertical.
 */

function sizeCalculable(option, hvIdx) {
  return option[HV_NAMES[hvIdx][0]] != null || option[HV_NAMES[hvIdx][1]] != null && option[HV_NAMES[hvIdx][2]] != null;
}
function fetchLayoutMode(ins) {
  var layoutMode = ins.layoutMode || ins.constructor.layoutMode;
  return isObject(layoutMode) ? layoutMode : layoutMode ? {
    type: layoutMode
  } : null;
}
/**
 * Consider Case:
 * When default option has {left: 0, width: 100}, and we set {right: 0}
 * through setOption or media query, using normal zrUtil.merge will cause
 * {right: 0} does not take effect.
 *
 * @example
 * ComponentModel.extend({
 *     init: function () {
 *         ...
 *         let inputPositionParams = layout.getLayoutParams(option);
 *         this.mergeOption(inputPositionParams);
 *     },
 *     mergeOption: function (newOption) {
 *         newOption && zrUtil.merge(thisOption, newOption, true);
 *         layout.mergeLayoutParam(thisOption, newOption);
 *     }
 * });
 *
 * @param targetOption
 * @param newOption
 * @param opt
 */

function mergeLayoutParam(targetOption, newOption, opt) {
  var ignoreSize = opt && opt.ignoreSize;
  !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);
  var hResult = merge(HV_NAMES[0], 0);
  var vResult = merge(HV_NAMES[1], 1);
  copy(HV_NAMES[0], targetOption, hResult);
  copy(HV_NAMES[1], targetOption, vResult);

  function merge(names, hvIdx) {
    var newParams = {};
    var newValueCount = 0;
    var merged = {};
    var mergedValueCount = 0;
    var enoughParamNumber = 2;
    layout_each(names, function (name) {
      merged[name] = targetOption[name];
    });
    layout_each(names, function (name) {
      // Consider case: newOption.width is null, which is
      // set by user for removing width setting.
      hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
      hasValue(newParams, name) && newValueCount++;
      hasValue(merged, name) && mergedValueCount++;
    });

    if (ignoreSize[hvIdx]) {
      // Only one of left/right is premitted to exist.
      if (hasValue(newOption, names[1])) {
        merged[names[2]] = null;
      } else if (hasValue(newOption, names[2])) {
        merged[names[1]] = null;
      }

      return merged;
    } // Case: newOption: {width: ..., right: ...},
    // or targetOption: {right: ...} and newOption: {width: ...},
    // There is no conflict when merged only has params count
    // little than enoughParamNumber.


    if (mergedValueCount === enoughParamNumber || !newValueCount) {
      return merged;
    } // Case: newOption: {width: ..., right: ...},
    // Than we can make sure user only want those two, and ignore
    // all origin params in targetOption.
    else if (newValueCount >= enoughParamNumber) {
        return newParams;
      } else {
        // Chose another param from targetOption by priority.
        for (var i = 0; i < names.length; i++) {
          var name_1 = names[i];

          if (!hasProp(newParams, name_1) && hasProp(targetOption, name_1)) {
            newParams[name_1] = targetOption[name_1];
            break;
          }
        }

        return newParams;
      }
  }

  function hasProp(obj, name) {
    return obj.hasOwnProperty(name);
  }

  function hasValue(obj, name) {
    return obj[name] != null && obj[name] !== 'auto';
  }

  function copy(names, target, source) {
    layout_each(names, function (name) {
      target[name] = source[name];
    });
  }
}
/**
 * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
 */

function getLayoutParams(source) {
  return copyLayoutParams({}, source);
}
/**
 * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
 * @param {Object} source
 * @return {Object} Result contains those props.
 */

function copyLayoutParams(target, source) {
  source && target && layout_each(LOCATION_PARAMS, function (name) {
    source.hasOwnProperty(name) && (target[name] = source[name]);
  });
  return target;
}
;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/TexturePool.js




var TexturePool = function () {

    this._pool = {};

    this._allocatedTextures = [];
};

TexturePool.prototype = {

    constructor: TexturePool,

    get: function (parameters) {
        var key = generateKey(parameters);
        if (!this._pool.hasOwnProperty(key)) {
            this._pool[key] = [];
        }
        var list = this._pool[key];
        if (!list.length) {
            var texture = new src_Texture2D(parameters);
            this._allocatedTextures.push(texture);
            return texture;
        }
        return list.pop();
    },

    put: function (texture) {
        var key = generateKey(texture);
        if (!this._pool.hasOwnProperty(key)) {
            this._pool[key] = [];
        }
        var list = this._pool[key];
        list.push(texture);
    },

    clear: function (renderer) {
        for (var i = 0; i < this._allocatedTextures.length; i++) {
            this._allocatedTextures[i].dispose(renderer);
        }
        this._pool = {};
        this._allocatedTextures = [];
    }
};

var defaultParams = {
    width: 512,
    height: 512,
    type: glenum.UNSIGNED_BYTE,
    format: glenum.RGBA,
    wrapS: glenum.CLAMP_TO_EDGE,
    wrapT: glenum.CLAMP_TO_EDGE,
    minFilter: glenum.LINEAR_MIPMAP_LINEAR,
    magFilter: glenum.LINEAR,
    useMipmap: true,
    anisotropic: 1,
    flipY: true,
    unpackAlignment: 4,
    premultiplyAlpha: false
};

var defaultParamPropList = Object.keys(defaultParams);

function generateKey(parameters) {
    core_util.defaultsWithPropList(parameters, defaultParams, defaultParamPropList);
    fallBack(parameters);

    var key = '';
    for (var i = 0; i < defaultParamPropList.length; i++) {
        var name = defaultParamPropList[i];
        var chunk = parameters[name].toString();
        key += chunk;
    }
    return key;
}

function fallBack(target) {

    var IPOT = TexturePool_isPowerOfTwo(target.width, target.height);

    if (target.format === glenum.DEPTH_COMPONENT) {
        target.useMipmap = false;
    }

    if (!IPOT || !target.useMipmap) {
        if (target.minFilter == glenum.NEAREST_MIPMAP_NEAREST ||
            target.minFilter == glenum.NEAREST_MIPMAP_LINEAR) {
            target.minFilter = glenum.NEAREST;
        } else if (
            target.minFilter == glenum.LINEAR_MIPMAP_LINEAR ||
            target.minFilter == glenum.LINEAR_MIPMAP_NEAREST
        ) {
            target.minFilter = glenum.LINEAR;
        }
    }
    if (!IPOT) {
        target.wrapS = glenum.CLAMP_TO_EDGE;
        target.wrapT = glenum.CLAMP_TO_EDGE;
    }
}

function TexturePool_isPowerOfTwo(width, height) {
    return (width & (width-1)) === 0 &&
            (height & (height-1)) === 0;
}

/* harmony default export */ const compositor_TexturePool = (TexturePool);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/shadowmap.glsl.js
/* harmony default export */ const shadowmap_glsl = ("@export clay.sm.depth.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nuniform vec2 uvRepeat = vec2(1.0, 1.0);\nuniform vec2 uvOffset = vec2(0.0, 0.0);\n@import clay.chunk.skinning_header\n@import clay.chunk.instancing_header\nvarying vec4 v_ViewPosition;\nvarying vec2 v_Texcoord;\nvoid main(){\n vec4 P = vec4(position, 1.0);\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n P = skinMatrixWS * P;\n#endif\n#ifdef INSTANCING\n @import clay.chunk.instancing_matrix\n P = instanceMat * P;\n#endif\n v_ViewPosition = worldViewProjection * P;\n gl_Position = v_ViewPosition;\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n}\n@end\n@export clay.sm.depth.fragment\nvarying vec4 v_ViewPosition;\nvarying vec2 v_Texcoord;\nuniform float bias : 0.001;\nuniform float slopeScale : 1.0;\nuniform sampler2D alphaMap;\nuniform float alphaCutoff: 0.0;\n@import clay.util.encode_float\nvoid main(){\n float depth = v_ViewPosition.z / v_ViewPosition.w;\n if (alphaCutoff > 0.0) {\n if (texture2D(alphaMap, v_Texcoord).a <= alphaCutoff) {\n discard;\n }\n }\n#ifdef USE_VSM\n depth = depth * 0.5 + 0.5;\n float moment1 = depth;\n float moment2 = depth * depth;\n #ifdef SUPPORT_STANDARD_DERIVATIVES\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n moment2 += 0.25*(dx*dx+dy*dy);\n #endif\n gl_FragColor = vec4(moment1, moment2, 0.0, 1.0);\n#else\n #ifdef SUPPORT_STANDARD_DERIVATIVES\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n depth += sqrt(dx*dx + dy*dy) * slopeScale + bias;\n #else\n depth += bias;\n #endif\n gl_FragColor = encodeFloat(depth * 0.5 + 0.5);\n#endif\n}\n@end\n@export clay.sm.debug_depth\nuniform sampler2D depthMap;\nvarying vec2 v_Texcoord;\n@import clay.util.decode_float\nvoid main() {\n vec4 tex = texture2D(depthMap, v_Texcoord);\n#ifdef USE_VSM\n gl_FragColor = vec4(tex.rgb, 1.0);\n#else\n float depth = decodeFloat(tex);\n gl_FragColor = vec4(depth, depth, depth, 1.0);\n#endif\n}\n@end\n@export clay.sm.distance.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvarying vec3 v_WorldPosition;\nvoid main (){\n vec4 P = vec4(position, 1.0);\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n P = skinMatrixWS * P;\n#endif\n#ifdef INSTANCING\n @import clay.chunk.instancing_matrix\n P = instanceMat * P;\n#endif\n gl_Position = worldViewProjection * P;\n v_WorldPosition = (world * P).xyz;\n}\n@end\n@export clay.sm.distance.fragment\nuniform vec3 lightPosition;\nuniform float range : 100;\nvarying vec3 v_WorldPosition;\n@import clay.util.encode_float\nvoid main(){\n float dist = distance(lightPosition, v_WorldPosition);\n#ifdef USE_VSM\n gl_FragColor = vec4(dist, dist * dist, 0.0, 0.0);\n#else\n dist = dist / range;\n gl_FragColor = encodeFloat(dist);\n#endif\n}\n@end\n@export clay.plugin.shadow_map_common\n@import clay.util.decode_float\nfloat tapShadowMap(sampler2D map, vec2 uv, float z){\n vec4 tex = texture2D(map, uv);\n return step(z, decodeFloat(tex) * 2.0 - 1.0);\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize, vec2 scale) {\n float shadowContrib = tapShadowMap(map, uv, z);\n vec2 offset = vec2(1.0 / textureSize) * scale;\n#ifdef PCF_KERNEL_SIZE\n for (int _idx_ = 0; _idx_ < PCF_KERNEL_SIZE; _idx_++) {{\n shadowContrib += tapShadowMap(map, uv + offset * pcfKernel[_idx_], z);\n }}\n return shadowContrib / float(PCF_KERNEL_SIZE + 1);\n#else\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, -offset.y), z);\n return shadowContrib / 9.0;\n#endif\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize) {\n return pcf(map, uv, z, textureSize, vec2(1.0));\n}\nfloat chebyshevUpperBound(vec2 moments, float z){\n float p = 0.0;\n z = z * 0.5 + 0.5;\n if (z <= moments.x) {\n p = 1.0;\n }\n float variance = moments.y - moments.x * moments.x;\n variance = max(variance, 0.0000001);\n float mD = moments.x - z;\n float pMax = variance / (variance + mD * mD);\n pMax = clamp((pMax-0.4)/(1.0-0.4), 0.0, 1.0);\n return max(p, pMax);\n}\nfloat computeShadowContrib(\n sampler2D map, mat4 lightVPM, vec3 position, float textureSize, vec2 scale, vec2 offset\n) {\n vec4 posInLightSpace = lightVPM * vec4(position, 1.0);\n posInLightSpace.xyz /= posInLightSpace.w;\n float z = posInLightSpace.z;\n if(all(greaterThan(posInLightSpace.xyz, vec3(-0.99, -0.99, -1.0))) &&\n all(lessThan(posInLightSpace.xyz, vec3(0.99, 0.99, 1.0)))){\n vec2 uv = (posInLightSpace.xy+1.0) / 2.0;\n #ifdef USE_VSM\n vec2 moments = texture2D(map, uv * scale + offset).xy;\n return chebyshevUpperBound(moments, z);\n #else\n return pcf(map, uv * scale + offset, z, textureSize, scale);\n #endif\n }\n return 1.0;\n}\nfloat computeShadowContrib(sampler2D map, mat4 lightVPM, vec3 position, float textureSize) {\n return computeShadowContrib(map, lightVPM, position, textureSize, vec2(1.0), vec2(0.0));\n}\nfloat computeShadowContribOmni(samplerCube map, vec3 direction, float range)\n{\n float dist = length(direction);\n vec4 shadowTex = textureCube(map, direction);\n#ifdef USE_VSM\n vec2 moments = shadowTex.xy;\n float variance = moments.y - moments.x * moments.x;\n float mD = moments.x - dist;\n float p = variance / (variance + mD * mD);\n if(moments.x + 0.001 < dist){\n return clamp(p, 0.0, 1.0);\n }else{\n return 1.0;\n }\n#else\n return step(dist, (decodeFloat(shadowTex) + 0.0002) * range);\n#endif\n}\n@end\n@export clay.plugin.compute_shadow_map\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT) || defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT) || defined(POINT_LIGHT_SHADOWMAP_COUNT)\n#ifdef SPOT_LIGHT_SHADOWMAP_COUNT\nuniform sampler2D spotLightShadowMaps[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 spotLightMatrices[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float spotLightShadowMapSizes[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#ifdef DIRECTIONAL_LIGHT_SHADOWMAP_COUNT\n#if defined(SHADOW_CASCADE)\nuniform sampler2D directionalLightShadowMaps[1]:unconfigurable;\nuniform mat4 directionalLightMatrices[SHADOW_CASCADE]:unconfigurable;\nuniform float directionalLightShadowMapSizes[1]:unconfigurable;\nuniform float shadowCascadeClipsNear[SHADOW_CASCADE]:unconfigurable;\nuniform float shadowCascadeClipsFar[SHADOW_CASCADE]:unconfigurable;\n#else\nuniform sampler2D directionalLightShadowMaps[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 directionalLightMatrices[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float directionalLightShadowMapSizes[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#endif\n#ifdef POINT_LIGHT_SHADOWMAP_COUNT\nuniform samplerCube pointLightShadowMaps[POINT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\nuniform bool shadowEnabled : true;\n#ifdef PCF_KERNEL_SIZE\nuniform vec2 pcfKernel[PCF_KERNEL_SIZE];\n#endif\n@import clay.plugin.shadow_map_common\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfSpotLights(vec3 position, inout float shadowContribs[SPOT_LIGHT_COUNT] ) {\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < SPOT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n spotLightShadowMaps[_idx_], spotLightMatrices[_idx_], position,\n spotLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = SPOT_LIGHT_SHADOWMAP_COUNT; _idx_ < SPOT_LIGHT_COUNT; _idx_++){{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n#ifdef SHADOW_CASCADE\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float depth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far)\n / (gl_DepthRange.far - gl_DepthRange.near);\n float shadowContrib;\n shadowContribs[0] = 1.0;\n for (int _idx_ = 0; _idx_ < SHADOW_CASCADE; _idx_++) {{\n if (\n depth >= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/prePass/ShadowMap.js





















var ShadowMap_targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz'];


src_Shader.import(shadowmap_glsl);

function getDepthMaterialUniform(renderable, depthMaterial, symbol) {
    if (symbol === 'alphaMap') {
        return renderable.material.get('diffuseMap');
    }
    else if (symbol === 'alphaCutoff') {
        if (renderable.material.isDefined('fragment', 'ALPHA_TEST')
            && renderable.material.get('diffuseMap')
        ) {
            var alphaCutoff = renderable.material.get('alphaCutoff');
            return alphaCutoff || 0;
        }
        return 0;
    }
    else if (symbol === 'uvRepeat') {
        return renderable.material.get('uvRepeat');
    }
    else if (symbol === 'uvOffset') {
        return renderable.material.get('uvOffset');
    }
    else {
        return depthMaterial.get(symbol);
    }
}

function isDepthMaterialChanged(renderable, prevRenderable) {
    var matA = renderable.material;
    var matB = prevRenderable.material;
    return matA.get('diffuseMap') !== matB.get('diffuseMap')
        || (matA.get('alphaCutoff') || 0) !== (matB.get('alphaCutoff') || 0);
}

/**
 * Pass rendering shadow map.
 *
 * @constructor clay.prePass.ShadowMap
 * @extends clay.core.Base
 * @example
 *     var shadowMapPass = new clay.prePass.ShadowMap({
 *         softShadow: clay.prePass.ShadowMap.VSM
 *     });
 *     ...
 *     animation.on('frame', function (frameTime) {
 *         shadowMapPass.render(renderer, scene, camera);
 *         renderer.render(scene, camera);
 *     });
 */
var ShadowMapPass = core_Base.extend(function () {
    return /** @lends clay.prePass.ShadowMap# */ {
        /**
         * Soft shadow technique.
         * Can be {@link clay.prePass.ShadowMap.PCF} or {@link clay.prePass.ShadowMap.VSM}
         * @type {number}
         */
        softShadow: ShadowMapPass.PCF,

        /**
         * Soft shadow blur size
         * @type {number}
         */
        shadowBlur: 1.0,

        lightFrustumBias: 'auto',

        kernelPCF: new Float32Array([
            1, 0,
            1, 1,
            -1, 1,
            0, 1,
            -1, 0,
            -1, -1,
            1, -1,
            0, -1
        ]),

        precision: 'highp',

        _lastRenderNotCastShadow: false,

        _frameBuffer: new src_FrameBuffer(),

        _textures: {},
        _shadowMapNumber: {
            'POINT_LIGHT': 0,
            'DIRECTIONAL_LIGHT': 0,
            'SPOT_LIGHT': 0
        },

        _depthMaterials: {},
        _distanceMaterials: {},

        _receivers: [],
        _lightsCastShadow: [],

        _lightCameras: {},
        _lightMaterials: {},

        _texturePool: new compositor_TexturePool()
    };
}, function () {
    // Gaussian filter pass for VSM
    this._gaussianPassH = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.gaussian_blur')
    });
    this._gaussianPassV = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.gaussian_blur')
    });
    this._gaussianPassH.setUniform('blurSize', this.shadowBlur);
    this._gaussianPassH.setUniform('blurDir', 0.0);
    this._gaussianPassV.setUniform('blurSize', this.shadowBlur);
    this._gaussianPassV.setUniform('blurDir', 1.0);

    this._outputDepthPass = new compositor_Pass({
        fragment: src_Shader.source('clay.sm.debug_depth')
    });
}, {
    /**
     * Render scene to shadow textures
     * @param  {clay.Renderer} renderer
     * @param  {clay.Scene} scene
     * @param  {clay.Camera} sceneCamera
     * @param  {boolean} [notUpdateScene=false]
     * @memberOf clay.prePass.ShadowMap.prototype
     */
    render: function (renderer, scene, sceneCamera, notUpdateScene) {
        if (!sceneCamera) {
            sceneCamera = scene.getMainCamera();
        }
        this.trigger('beforerender', this, renderer, scene, sceneCamera);
        this._renderShadowPass(renderer, scene, sceneCamera, notUpdateScene);
        this.trigger('afterrender', this, renderer, scene, sceneCamera);
    },

    /**
     * Debug rendering of shadow textures
     * @param  {clay.Renderer} renderer
     * @param  {number} size
     * @memberOf clay.prePass.ShadowMap.prototype
     */
    renderDebug: function (renderer, size) {
        renderer.saveClear();
        var viewport = renderer.viewport;
        var x = 0, y = 0;
        var width = size || viewport.width / 4;
        var height = width;
        if (this.softShadow === ShadowMapPass.VSM) {
            this._outputDepthPass.material.define('fragment', 'USE_VSM');
        }
        else {
            this._outputDepthPass.material.undefine('fragment', 'USE_VSM');
        }
        for (var name in this._textures) {
            var texture = this._textures[name];
            renderer.setViewport(x, y, width * texture.width / texture.height, height);
            this._outputDepthPass.setUniform('depthMap', texture);
            this._outputDepthPass.render(renderer);
            x += width * texture.width / texture.height;
        }
        renderer.setViewport(viewport);
        renderer.restoreClear();
    },

    _updateReceivers: function (renderer, mesh) {
        if (mesh.receiveShadow) {
            this._receivers.push(mesh);
            mesh.material.set('shadowEnabled', 1);

            mesh.material.set('pcfKernel', this.kernelPCF);
        }
        else {
            mesh.material.set('shadowEnabled', 0);
        }

        if (this.softShadow === ShadowMapPass.VSM) {
            mesh.material.define('fragment', 'USE_VSM');
            mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE');
        }
        else {
            mesh.material.undefine('fragment', 'USE_VSM');
            var kernelPCF = this.kernelPCF;
            if (kernelPCF && kernelPCF.length) {
                mesh.material.define('fragment', 'PCF_KERNEL_SIZE', kernelPCF.length / 2);
            }
            else {
                mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE');
            }
        }
    },

    _update: function (renderer, scene) {
        var self = this;
        scene.traverse(function (renderable) {
            if (renderable.isRenderable()) {
                self._updateReceivers(renderer, renderable);
            }
        });

        for (var i = 0; i < scene.lights.length; i++) {
            var light = scene.lights[i];
            if (light.castShadow && !light.invisible) {
                this._lightsCastShadow.push(light);
            }
        }
    },

    _renderShadowPass: function (renderer, scene, sceneCamera, notUpdateScene) {
        // reset
        for (var name in this._shadowMapNumber) {
            this._shadowMapNumber[name] = 0;
        }
        this._lightsCastShadow.length = 0;
        this._receivers.length = 0;

        var _gl = renderer.gl;

        if (!notUpdateScene) {
            scene.update();
        }
        if (sceneCamera) {
            sceneCamera.update();
        }

        scene.updateLights();
        this._update(renderer, scene);

        // Needs to update the receivers again if shadows come from 1 to 0.
        if (!this._lightsCastShadow.length && this._lastRenderNotCastShadow) {
            return;
        }

        this._lastRenderNotCastShadow = this._lightsCastShadow === 0;

        _gl.enable(_gl.DEPTH_TEST);
        _gl.depthMask(true);
        _gl.disable(_gl.BLEND);

        // Clear with high-z, so the part not rendered will not been shadowed
        // TODO
        // TODO restore
        _gl.clearColor(1.0, 1.0, 1.0, 1.0);

        // Shadow uniforms
        var spotLightShadowMaps = [];
        var spotLightMatrices = [];
        var directionalLightShadowMaps = [];
        var directionalLightMatrices = [];
        var shadowCascadeClips = [];
        var pointLightShadowMaps = [];

        var dirLightHasCascade;
        // Create textures for shadow map
        for (var i = 0; i < this._lightsCastShadow.length; i++) {
            var light = this._lightsCastShadow[i];
            if (light.type === 'DIRECTIONAL_LIGHT') {

                if (dirLightHasCascade) {
                    console.warn('Only one direectional light supported with shadow cascade');
                    continue;
                }
                if (light.shadowCascade > 4) {
                    console.warn('Support at most 4 cascade');
                    continue;
                }
                if (light.shadowCascade > 1) {
                    dirLightHasCascade = light;
                }

                this.renderDirectionalLightShadow(
                    renderer,
                    scene,
                    sceneCamera,
                    light,
                    shadowCascadeClips,
                    directionalLightMatrices,
                    directionalLightShadowMaps
                );
            }
            else if (light.type === 'SPOT_LIGHT') {
                this.renderSpotLightShadow(
                    renderer,
                    scene,
                    light,
                    spotLightMatrices,
                    spotLightShadowMaps
                );
            }
            else if (light.type === 'POINT_LIGHT') {
                this.renderPointLightShadow(
                    renderer,
                    scene,
                    light,
                    pointLightShadowMaps
                );
            }

            this._shadowMapNumber[light.type]++;
        }

        for (var lightType in this._shadowMapNumber) {
            var number = this._shadowMapNumber[lightType];
            var key = lightType + '_SHADOWMAP_COUNT';
            for (var i = 0; i < this._receivers.length; i++) {
                var mesh = this._receivers[i];
                var material = mesh.material;
                if (material.fragmentDefines[key] !== number) {
                    if (number > 0) {
                        material.define('fragment', key, number);
                    }
                    else if (material.isDefined('fragment', key)) {
                        material.undefine('fragment', key);
                    }
                }
            }
        }
        for (var i = 0; i < this._receivers.length; i++) {
            var mesh = this._receivers[i];
            var material = mesh.material;
            if (dirLightHasCascade) {
                material.define('fragment', 'SHADOW_CASCADE', dirLightHasCascade.shadowCascade);
            }
            else {
                material.undefine('fragment', 'SHADOW_CASCADE');
            }
        }

        var shadowUniforms = scene.shadowUniforms;

        function getSize(texture) {
            return texture.height;
        }
        if (directionalLightShadowMaps.length > 0) {
            var directionalLightShadowMapSizes = directionalLightShadowMaps.map(getSize);
            shadowUniforms.directionalLightShadowMaps = { value: directionalLightShadowMaps, type: 'tv' };
            shadowUniforms.directionalLightMatrices = { value: directionalLightMatrices, type: 'm4v' };
            shadowUniforms.directionalLightShadowMapSizes = { value: directionalLightShadowMapSizes, type: '1fv' };
            if (dirLightHasCascade) {
                var shadowCascadeClipsNear = shadowCascadeClips.slice();
                var shadowCascadeClipsFar = shadowCascadeClips.slice();
                shadowCascadeClipsNear.pop();
                shadowCascadeClipsFar.shift();

                // Iterate from far to near
                shadowCascadeClipsNear.reverse();
                shadowCascadeClipsFar.reverse();
                // directionalLightShadowMaps.reverse();
                directionalLightMatrices.reverse();
                shadowUniforms.shadowCascadeClipsNear = { value: shadowCascadeClipsNear, type: '1fv' };
                shadowUniforms.shadowCascadeClipsFar = { value: shadowCascadeClipsFar, type: '1fv' };
            }
        }

        if (spotLightShadowMaps.length > 0) {
            var spotLightShadowMapSizes = spotLightShadowMaps.map(getSize);
            var shadowUniforms = scene.shadowUniforms;
            shadowUniforms.spotLightShadowMaps = { value: spotLightShadowMaps, type: 'tv' };
            shadowUniforms.spotLightMatrices = { value: spotLightMatrices, type: 'm4v' };
            shadowUniforms.spotLightShadowMapSizes = { value: spotLightShadowMapSizes, type: '1fv' };
        }

        if (pointLightShadowMaps.length > 0) {
            shadowUniforms.pointLightShadowMaps = { value: pointLightShadowMaps, type: 'tv' };
        }
    },

    renderDirectionalLightShadow: (function () {

        var splitFrustum = new math_Frustum();
        var splitProjMatrix = new math_Matrix4();
        var cropBBox = new math_BoundingBox();
        var cropMatrix = new math_Matrix4();
        var lightViewMatrix = new math_Matrix4();
        var lightViewProjMatrix = new math_Matrix4();
        var lightProjMatrix = new math_Matrix4();

        return function (renderer, scene, sceneCamera, light, shadowCascadeClips, directionalLightMatrices, directionalLightShadowMaps) {

            var defaultShadowMaterial = this._getDepthMaterial(light);
            var passConfig = {
                getMaterial: function (renderable) {
                    return renderable.shadowDepthMaterial || defaultShadowMaterial;
                },
                isMaterialChanged: isDepthMaterialChanged,
                getUniform: getDepthMaterialUniform,
                ifRender: function (renderable) {
                    return renderable.castShadow;
                },
                sortCompare: src_Renderer.opaqueSortCompare
            };

            // First frame
            if (!scene.viewBoundingBoxLastFrame.isFinite()) {
                var boundingBox = scene.getBoundingBox();
                scene.viewBoundingBoxLastFrame
                    .copy(boundingBox).applyTransform(sceneCamera.viewMatrix);
            }
            // Considering moving speed since the bounding box is from last frame
            // TODO: add a bias
            var clippedFar = Math.min(-scene.viewBoundingBoxLastFrame.min.z, sceneCamera.far);
            var clippedNear = Math.max(-scene.viewBoundingBoxLastFrame.max.z, sceneCamera.near);

            var lightCamera = this._getDirectionalLightCamera(light, scene, sceneCamera);

            var lvpMat4Arr = lightViewProjMatrix.array;
            lightProjMatrix.copy(lightCamera.projectionMatrix);
            glmatrix_mat4.invert(lightViewMatrix.array, lightCamera.worldTransform.array);
            glmatrix_mat4.multiply(lightViewMatrix.array, lightViewMatrix.array, sceneCamera.worldTransform.array);
            glmatrix_mat4.multiply(lvpMat4Arr, lightProjMatrix.array, lightViewMatrix.array);

            var clipPlanes = [];
            var isPerspective = sceneCamera instanceof camera_Perspective;

            var scaleZ = (sceneCamera.near + sceneCamera.far) / (sceneCamera.near - sceneCamera.far);
            var offsetZ = 2 * sceneCamera.near * sceneCamera.far / (sceneCamera.near - sceneCamera.far);
            for (var i = 0; i <= light.shadowCascade; i++) {
                var clog = clippedNear * Math.pow(clippedFar / clippedNear, i / light.shadowCascade);
                var cuni = clippedNear + (clippedFar - clippedNear) * i / light.shadowCascade;
                var c = clog * light.cascadeSplitLogFactor + cuni * (1 - light.cascadeSplitLogFactor);
                clipPlanes.push(c);
                shadowCascadeClips.push(-(-c * scaleZ + offsetZ) / -c);
            }
            var texture = this._getTexture(light, light.shadowCascade);
            directionalLightShadowMaps.push(texture);

            var viewport = renderer.viewport;

            var _gl = renderer.gl;
            this._frameBuffer.attach(texture);
            this._frameBuffer.bind(renderer);
            _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT);

            for (var i = 0; i < light.shadowCascade; i++) {
                // Get the splitted frustum
                var nearPlane = clipPlanes[i];
                var farPlane = clipPlanes[i + 1];
                if (isPerspective) {
                    glmatrix_mat4.perspective(splitProjMatrix.array, sceneCamera.fov / 180 * Math.PI, sceneCamera.aspect, nearPlane, farPlane);
                }
                else {
                    glmatrix_mat4.ortho(
                        splitProjMatrix.array,
                        sceneCamera.left, sceneCamera.right, sceneCamera.bottom, sceneCamera.top,
                        nearPlane, farPlane
                    );
                }
                splitFrustum.setFromProjection(splitProjMatrix);
                splitFrustum.getTransformedBoundingBox(cropBBox, lightViewMatrix);
                cropBBox.applyProjection(lightProjMatrix);
                var _min = cropBBox.min.array;
                var _max = cropBBox.max.array;
                _min[0] = Math.max(_min[0], -1);
                _min[1] = Math.max(_min[1], -1);
                _max[0] = Math.min(_max[0], 1);
                _max[1] = Math.min(_max[1], 1);
                cropMatrix.ortho(_min[0], _max[0], _min[1], _max[1], 1, -1);
                lightCamera.projectionMatrix.multiplyLeft(cropMatrix);

                var shadowSize = light.shadowResolution || 512;

                // Reversed, left to right => far to near
                renderer.setViewport((light.shadowCascade - i - 1) * shadowSize, 0, shadowSize, shadowSize, 1);

                var renderList = scene.updateRenderList(lightCamera);
                renderer.renderPass(renderList.opaque, lightCamera, passConfig);

                // Filter for VSM
                if (this.softShadow === ShadowMapPass.VSM) {
                    this._gaussianFilter(renderer, texture, texture.width);
                }

                var matrix = new math_Matrix4();
                matrix.copy(lightCamera.viewMatrix)
                    .multiplyLeft(lightCamera.projectionMatrix);

                directionalLightMatrices.push(matrix.array);

                lightCamera.projectionMatrix.copy(lightProjMatrix);
            }

            this._frameBuffer.unbind(renderer);

            renderer.setViewport(viewport);
        };
    })(),

    renderSpotLightShadow: function (renderer, scene, light, spotLightMatrices, spotLightShadowMaps) {

        var texture = this._getTexture(light);
        var lightCamera = this._getSpotLightCamera(light);
        var _gl = renderer.gl;

        this._frameBuffer.attach(texture);
        this._frameBuffer.bind(renderer);

        _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT);

        var defaultShadowMaterial = this._getDepthMaterial(light);
        var passConfig = {
            getMaterial: function (renderable) {
                return renderable.shadowDepthMaterial || defaultShadowMaterial;
            },
            isMaterialChanged: isDepthMaterialChanged,
            getUniform: getDepthMaterialUniform,
            ifRender: function (renderable) {
                return renderable.castShadow;
            },
            sortCompare: src_Renderer.opaqueSortCompare
        };

        var renderList = scene.updateRenderList(lightCamera);
        renderer.renderPass(renderList.opaque, lightCamera, passConfig);

        this._frameBuffer.unbind(renderer);

        // Filter for VSM
        if (this.softShadow === ShadowMapPass.VSM) {
            this._gaussianFilter(renderer, texture, texture.width);
        }

        var matrix = new math_Matrix4();
        matrix.copy(lightCamera.worldTransform)
            .invert()
            .multiplyLeft(lightCamera.projectionMatrix);

        spotLightShadowMaps.push(texture);
        spotLightMatrices.push(matrix.array);
    },

    renderPointLightShadow: function (renderer, scene, light, pointLightShadowMaps) {
        var texture = this._getTexture(light);
        var _gl = renderer.gl;
        pointLightShadowMaps.push(texture);

        var defaultShadowMaterial = this._getDepthMaterial(light);
        var passConfig = {
            getMaterial: function (renderable) {
                return renderable.shadowDepthMaterial || defaultShadowMaterial;
            },
            getUniform: getDepthMaterialUniform,
            sortCompare: src_Renderer.opaqueSortCompare
        };

        var renderListEachSide = {
            px: [], py: [], pz: [], nx: [], ny: [], nz: []
        };
        var bbox = new math_BoundingBox();
        var lightWorldPosition = light.getWorldPosition().array;
        var lightBBox = new math_BoundingBox();
        var range = light.range;
        lightBBox.min.setArray(lightWorldPosition);
        lightBBox.max.setArray(lightWorldPosition);
        var extent = new math_Vector3(range, range, range);
        lightBBox.max.add(extent);
        lightBBox.min.sub(extent);

        var targetsNeedRender = { px: false, py: false, pz: false, nx: false, ny: false, nz: false };
        scene.traverse(function (renderable) {
            if (renderable.isRenderable() && renderable.castShadow) {
                var geometry = renderable.geometry;
                if (!geometry.boundingBox) {
                    for (var i = 0; i < ShadowMap_targets.length; i++) {
                        renderListEachSide[ShadowMap_targets[i]].push(renderable);
                    }
                    return;
                }
                bbox.transformFrom(geometry.boundingBox, renderable.worldTransform);
                if (!bbox.intersectBoundingBox(lightBBox)) {
                    return;
                }

                bbox.updateVertices();
                for (var i = 0; i < ShadowMap_targets.length; i++) {
                    targetsNeedRender[ShadowMap_targets[i]] = false;
                }
                for (var i = 0; i < 8; i++) {
                    var vtx = bbox.vertices[i];
                    var x = vtx[0] - lightWorldPosition[0];
                    var y = vtx[1] - lightWorldPosition[1];
                    var z = vtx[2] - lightWorldPosition[2];
                    var absx = Math.abs(x);
                    var absy = Math.abs(y);
                    var absz = Math.abs(z);
                    if (absx > absy) {
                        if (absx > absz) {
                            targetsNeedRender[x > 0 ? 'px' : 'nx'] = true;
                        }
                        else {
                            targetsNeedRender[z > 0 ? 'pz' : 'nz'] = true;
                        }
                    }
                    else {
                        if (absy > absz) {
                            targetsNeedRender[y > 0 ? 'py' : 'ny'] = true;
                        }
                        else {
                            targetsNeedRender[z > 0 ? 'pz' : 'nz'] = true;
                        }
                    }
                }
                for (var i = 0; i < ShadowMap_targets.length; i++) {
                    if (targetsNeedRender[ShadowMap_targets[i]]) {
                        renderListEachSide[ShadowMap_targets[i]].push(renderable);
                    }
                }
            }
        });

        for (var i = 0; i < 6; i++) {
            var target = ShadowMap_targets[i];
            var camera = this._getPointLightCamera(light, target);

            this._frameBuffer.attach(texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i);
            this._frameBuffer.bind(renderer);
            _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT);

            renderer.renderPass(renderListEachSide[target], camera, passConfig);
        }

        this._frameBuffer.unbind(renderer);
    },

    _getDepthMaterial: function (light) {
        var shadowMaterial = this._lightMaterials[light.__uid__];
        var isPointLight = light.type === 'POINT_LIGHT';
        if (!shadowMaterial) {
            var shaderPrefix = isPointLight ? 'clay.sm.distance.' : 'clay.sm.depth.';
            shadowMaterial = new src_Material({
                precision: this.precision,
                shader: new src_Shader(src_Shader.source(shaderPrefix + 'vertex'), src_Shader.source(shaderPrefix + 'fragment'))
            });

            this._lightMaterials[light.__uid__] = shadowMaterial;
        }
        if (light.shadowSlopeScale != null) {
            shadowMaterial.setUniform('slopeScale', light.shadowSlopeScale);
        }
        if (light.shadowBias != null) {
            shadowMaterial.setUniform('bias', light.shadowBias);
        }
        if (this.softShadow === ShadowMapPass.VSM) {
            shadowMaterial.define('fragment', 'USE_VSM');
        }
        else {
            shadowMaterial.undefine('fragment', 'USE_VSM');
        }

        if (isPointLight) {
            shadowMaterial.set('lightPosition', light.getWorldPosition().array);
            shadowMaterial.set('range', light.range);
        }

        return shadowMaterial;
    },

    _gaussianFilter: function (renderer, texture, size) {
        var parameter = {
            width: size,
            height: size,
            type: src_Texture.FLOAT
        };
        var tmpTexture = this._texturePool.get(parameter);

        this._frameBuffer.attach(tmpTexture);
        this._frameBuffer.bind(renderer);
        this._gaussianPassH.setUniform('texture', texture);
        this._gaussianPassH.setUniform('textureWidth', size);
        this._gaussianPassH.render(renderer);

        this._frameBuffer.attach(texture);
        this._gaussianPassV.setUniform('texture', tmpTexture);
        this._gaussianPassV.setUniform('textureHeight', size);
        this._gaussianPassV.render(renderer);
        this._frameBuffer.unbind(renderer);

        this._texturePool.put(tmpTexture);
    },

    _getTexture: function (light, cascade) {
        var key = light.__uid__;
        var texture = this._textures[key];
        var resolution = light.shadowResolution || 512;
        cascade = cascade || 1;
        if (!texture) {
            if (light.type === 'POINT_LIGHT') {
                texture = new src_TextureCube();
            }
            else {
                texture = new src_Texture2D();
            }
            // At most 4 cascade
            // TODO share with height ?
            texture.width = resolution * cascade;
            texture.height = resolution;
            if (this.softShadow === ShadowMapPass.VSM) {
                texture.type = src_Texture.FLOAT;
                texture.anisotropic = 4;
            }
            else {
                texture.minFilter = glenum.NEAREST;
                texture.magFilter = glenum.NEAREST;
                texture.useMipmap = false;
            }
            this._textures[key] = texture;
        }

        return texture;
    },

    _getPointLightCamera: function (light, target) {
        if (!this._lightCameras.point) {
            this._lightCameras.point = {
                px: new camera_Perspective(),
                nx: new camera_Perspective(),
                py: new camera_Perspective(),
                ny: new camera_Perspective(),
                pz: new camera_Perspective(),
                nz: new camera_Perspective()
            };
        }
        var camera = this._lightCameras.point[target];

        camera.far = light.range;
        camera.fov = 90;
        camera.position.set(0, 0, 0);
        switch (target) {
            case 'px':
                camera.lookAt(math_Vector3.POSITIVE_X, math_Vector3.NEGATIVE_Y);
                break;
            case 'nx':
                camera.lookAt(math_Vector3.NEGATIVE_X, math_Vector3.NEGATIVE_Y);
                break;
            case 'py':
                camera.lookAt(math_Vector3.POSITIVE_Y, math_Vector3.POSITIVE_Z);
                break;
            case 'ny':
                camera.lookAt(math_Vector3.NEGATIVE_Y, math_Vector3.NEGATIVE_Z);
                break;
            case 'pz':
                camera.lookAt(math_Vector3.POSITIVE_Z, math_Vector3.NEGATIVE_Y);
                break;
            case 'nz':
                camera.lookAt(math_Vector3.NEGATIVE_Z, math_Vector3.NEGATIVE_Y);
                break;
        }
        light.getWorldPosition(camera.position);
        camera.update();

        return camera;
    },

    _getDirectionalLightCamera: (function () {
        var lightViewMatrix = new math_Matrix4();
        var sceneViewBoundingBox = new math_BoundingBox();
        var lightViewBBox = new math_BoundingBox();
        // Camera of directional light will be adjusted
        // to contain the view frustum and scene bounding box as tightly as possible
        return function (light, scene, sceneCamera) {
            if (!this._lightCameras.directional) {
                this._lightCameras.directional = new camera_Orthographic();
            }
            var camera = this._lightCameras.directional;

            sceneViewBoundingBox.copy(scene.viewBoundingBoxLastFrame);
            sceneViewBoundingBox.intersection(sceneCamera.frustum.boundingBox);
            // Move to the center of frustum(in world space)
            camera.position
                .copy(sceneViewBoundingBox.min)
                .add(sceneViewBoundingBox.max)
                .scale(0.5)
                .transformMat4(sceneCamera.worldTransform);
            camera.rotation.copy(light.rotation);
            camera.scale.copy(light.scale);
            camera.updateWorldTransform();

            // Transform to light view space
            math_Matrix4.invert(lightViewMatrix, camera.worldTransform);
            math_Matrix4.multiply(lightViewMatrix, lightViewMatrix, sceneCamera.worldTransform);

            lightViewBBox.copy(sceneViewBoundingBox).applyTransform(lightViewMatrix);

            var min = lightViewBBox.min.array;
            var max = lightViewBBox.max.array;

            // Move camera to adjust the near to 0
            camera.position.set((min[0] + max[0]) / 2, (min[1] + max[1]) / 2, max[2])
                .transformMat4(camera.worldTransform);
            camera.near = 0;
            camera.far = -min[2] + max[2];
            // Make sure receivers not in the frustum will stil receive the shadow.
            if (isNaN(this.lightFrustumBias)) {
                camera.far *= 4;
            }
            else {
                camera.far += this.lightFrustumBias;
            }
            camera.left = min[0];
            camera.right = max[0];
            camera.top = max[1];
            camera.bottom = min[1];
            camera.update(true);

            return camera;
        };
    })(),

    _getSpotLightCamera: function (light) {
        if (!this._lightCameras.spot) {
            this._lightCameras.spot = new camera_Perspective();
        }
        var camera = this._lightCameras.spot;
        // Update properties
        camera.fov = light.penumbraAngle * 2;
        camera.far = light.range;
        camera.worldTransform.copy(light.worldTransform);
        camera.updateProjectionMatrix();
        glmatrix_mat4.invert(camera.viewMatrix.array, camera.worldTransform.array);

        return camera;
    },

    /**
     * @param  {clay.Renderer|WebGLRenderingContext} [renderer]
     * @memberOf clay.prePass.ShadowMap.prototype
     */
    // PENDING Renderer or WebGLRenderingContext
    dispose: function (renderer) {
        var _gl = renderer.gl || renderer;

        if (this._frameBuffer) {
            this._frameBuffer.dispose(_gl);
        }

        for (var name in this._textures) {
            this._textures[name].dispose(_gl);
        }

        this._texturePool.clear(renderer.gl);

        this._depthMaterials = {};
        this._distanceMaterials = {};
        this._textures = {};
        this._lightCameras = {};
        this._shadowMapNumber = {
            'POINT_LIGHT': 0,
            'DIRECTIONAL_LIGHT': 0,
            'SPOT_LIGHT': 0
        };
        this._meshMaterials = {};

        for (var i = 0; i < this._receivers.length; i++) {
            var mesh = this._receivers[i];
            // Mesh may be disposed
            if (mesh.material) {
                var material = mesh.material;
                material.undefine('fragment', 'POINT_LIGHT_SHADOW_COUNT');
                material.undefine('fragment', 'DIRECTIONAL_LIGHT_SHADOW_COUNT');
                material.undefine('fragment', 'AMBIENT_LIGHT_SHADOW_COUNT');
                material.set('shadowEnabled', 0);
            }
        }

        this._receivers = [];
        this._lightsCastShadow = [];
    }
});

/**
 * @name clay.prePass.ShadowMap.VSM
 * @type {number}
 */
ShadowMapPass.VSM = 1;

/**
 * @name clay.prePass.ShadowMap.PCF
 * @type {number}
 */
ShadowMapPass.PCF = 2;

/* harmony default export */ const ShadowMap = (ShadowMapPass);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/CompositorNode.js


// PENDING
// Use topological sort ?

/**
 * Node of graph based post processing.
 *
 * @constructor clay.compositor.CompositorNode
 * @extends clay.core.Base
 *
 */
var CompositorNode = core_Base.extend(function () {
    return /** @lends clay.compositor.CompositorNode# */ {
        /**
         * @type {string}
         */
        name: '',

        /**
         * Input links, will be updated by the graph
         * @example:
         *     inputName: {
         *         node: someNode,
         *         pin: 'xxxx'
         *     }
         * @type {Object}
         */
        inputLinks: {},

        /**
         * Output links, will be updated by the graph
         * @example:
         *     outputName: {
         *         node: someNode,
         *         pin: 'xxxx'
         *     }
         * @type {Object}
         */
        outputLinks: {},

        // Save the output texture of previous frame
        // Will be used when there exist a circular reference
        _prevOutputTextures: {},
        _outputTextures: {},

        // Example: { name: 2 }
        _outputReferences: {},

        _rendering: false,
        // If rendered in this frame
        _rendered: false,

        _compositor: null
    };
},
/** @lends clay.compositor.CompositorNode.prototype */
{

    // TODO Remove parameter function callback
    updateParameter: function (outputName, renderer) {
        var outputInfo = this.outputs[outputName];
        var parameters = outputInfo.parameters;
        var parametersCopy = outputInfo._parametersCopy;
        if (!parametersCopy) {
            parametersCopy = outputInfo._parametersCopy = {};
        }
        if (parameters) {
            for (var key in parameters) {
                if (key !== 'width' && key !== 'height') {
                    parametersCopy[key] = parameters[key];
                }
            }
        }
        var width, height;
        if (parameters.width instanceof Function) {
            width = parameters.width.call(this, renderer);
        }
        else {
            width = parameters.width;
        }
        if (parameters.height instanceof Function) {
            height = parameters.height.call(this, renderer);
        }
        else {
            height = parameters.height;
        }
        if (
            parametersCopy.width !== width
            || parametersCopy.height !== height
        ) {
            if (this._outputTextures[outputName]) {
                this._outputTextures[outputName].dispose(renderer.gl);
            }
        }
        parametersCopy.width = width;
        parametersCopy.height = height;

        return parametersCopy;
    },

    /**
     * Set parameter
     * @param {string} name
     * @param {} value
     */
    setParameter: function (name, value) {},
    /**
     * Get parameter value
     * @param  {string} name
     * @return {}
     */
    getParameter: function (name) {},
    /**
     * Set parameters
     * @param {Object} obj
     */
    setParameters: function (obj) {
        for (var name in obj) {
            this.setParameter(name, obj[name]);
        }
    },

    render: function () {},

    getOutput: function (renderer /*optional*/, name) {
        if (name == null) {
            // Return the output texture without rendering
            name = renderer;
            return this._outputTextures[name];
        }
        var outputInfo = this.outputs[name];
        if (!outputInfo) {
            return ;
        }

        // Already been rendered in this frame
        if (this._rendered) {
            // Force return texture in last frame
            if (outputInfo.outputLastFrame) {
                return this._prevOutputTextures[name];
            }
            else {
                return this._outputTextures[name];
            }
        }
        else if (
            // TODO
            this._rendering   // Solve Circular Reference
        ) {
            if (!this._prevOutputTextures[name]) {
                // Create a blank texture at first pass
                this._prevOutputTextures[name] = this._compositor.allocateTexture(outputInfo.parameters || {});
            }
            return this._prevOutputTextures[name];
        }

        this.render(renderer);

        return this._outputTextures[name];
    },

    removeReference: function (outputName) {
        this._outputReferences[outputName]--;
        if (this._outputReferences[outputName] === 0) {
            var outputInfo = this.outputs[outputName];
            if (outputInfo.keepLastFrame) {
                if (this._prevOutputTextures[outputName]) {
                    this._compositor.releaseTexture(this._prevOutputTextures[outputName]);
                }
                this._prevOutputTextures[outputName] = this._outputTextures[outputName];
            }
            else {
                // Output of this node have alreay been used by all other nodes
                // Put the texture back to the pool.
                this._compositor.releaseTexture(this._outputTextures[outputName]);
            }
        }
    },

    link: function (inputPinName, fromNode, fromPinName) {

        // The relationship from output pin to input pin is one-on-multiple
        this.inputLinks[inputPinName] = {
            node: fromNode,
            pin: fromPinName
        };
        if (!fromNode.outputLinks[fromPinName]) {
            fromNode.outputLinks[fromPinName] = [];
        }
        fromNode.outputLinks[fromPinName].push({
            node: this,
            pin: inputPinName
        });

        // Enabled the pin texture in shader
        this.pass.material.enableTexture(inputPinName);
    },

    clear: function () {
        this.inputLinks = {};
        this.outputLinks = {};
    },

    updateReference: function (outputName) {
        if (!this._rendering) {
            this._rendering = true;
            for (var inputName in this.inputLinks) {
                var link = this.inputLinks[inputName];
                link.node.updateReference(link.pin);
            }
            this._rendering = false;
        }
        if (outputName) {
            this._outputReferences[outputName] ++;
        }
    },

    beforeFrame: function () {
        this._rendered = false;

        for (var name in this.outputLinks) {
            this._outputReferences[name] = 0;
        }
    },

    afterFrame: function () {
        // Put back all the textures to pool
        for (var name in this.outputLinks) {
            if (this._outputReferences[name] > 0) {
                var outputInfo = this.outputs[name];
                if (outputInfo.keepLastFrame) {
                    if (this._prevOutputTextures[name]) {
                        this._compositor.releaseTexture(this._prevOutputTextures[name]);
                    }
                    this._prevOutputTextures[name] = this._outputTextures[name];
                }
                else {
                    this._compositor.releaseTexture(this._outputTextures[name]);
                }
            }
        }
    }
});

/* harmony default export */ const compositor_CompositorNode = (CompositorNode);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/Graph.js



/**
 * @constructor clay.compositor.Graph
 * @extends clay.core.Base
 */
var Graph = core_Base.extend(function () {
    return /** @lends clay.compositor.Graph# */ {
        /**
         * @type {Array.<clay.compositor.CompositorNode>}
         */
        nodes: []
    };
},
/** @lends clay.compositor.Graph.prototype */
{

    /**
     * Mark to update
     */
    dirty: function () {
        this._dirty = true;
    },
    /**
     * @param {clay.compositor.CompositorNode} node
     */
    addNode: function (node) {

        if (this.nodes.indexOf(node) >= 0) {
            return;
        }

        this.nodes.push(node);

        this._dirty = true;
    },
    /**
     * @param  {clay.compositor.CompositorNode|string} node
     */
    removeNode: function (node) {
        if (typeof node === 'string') {
            node = this.getNodeByName(node);
        }
        var idx = this.nodes.indexOf(node);
        if (idx >= 0) {
            this.nodes.splice(idx, 1);
            this._dirty = true;
        }
    },
    /**
     * @param {string} name
     * @return {clay.compositor.CompositorNode}
     */
    getNodeByName: function (name) {
        for (var i = 0; i < this.nodes.length; i++) {
            if (this.nodes[i].name === name) {
                return this.nodes[i];
            }
        }
    },
    /**
     * Update links of graph
     */
    update: function () {
        for (var i = 0; i < this.nodes.length; i++) {
            this.nodes[i].clear();
        }
        // Traverse all the nodes and build the graph
        for (var i = 0; i < this.nodes.length; i++) {
            var node = this.nodes[i];

            if (!node.inputs) {
                continue;
            }
            for (var inputName in node.inputs) {
                if (!node.inputs[inputName]) {
                    continue;
                }
                if (node.pass && !node.pass.material.isUniformEnabled(inputName)) {
                    console.warn('Pin '  + node.name + '.' + inputName + ' not used.');
                    continue;
                }
                var fromPinInfo = node.inputs[inputName];

                var fromPin = this.findPin(fromPinInfo);
                if (fromPin) {
                    node.link(inputName, fromPin.node, fromPin.pin);
                }
                else {
                    if (typeof fromPinInfo === 'string') {
                        console.warn('Node ' + fromPinInfo + ' not exist');
                    }
                    else {
                        console.warn('Pin of ' + fromPinInfo.node + '.' + fromPinInfo.pin + ' not exist');
                    }
                }
            }
        }
    },

    findPin: function (input) {
        var node;
        // Try to take input as a directly a node
        if (typeof input === 'string' || input instanceof compositor_CompositorNode) {
            input = {
                node: input
            };
        }

        if (typeof input.node === 'string') {
            for (var i = 0; i < this.nodes.length; i++) {
                var tmp = this.nodes[i];
                if (tmp.name === input.node) {
                    node = tmp;
                }
            }
        }
        else {
            node = input.node;
        }
        if (node) {
            var inputPin = input.pin;
            if (!inputPin) {
                // Use first pin defaultly
                if (node.outputs) {
                    inputPin = Object.keys(node.outputs)[0];
                }
            }
            if (node.outputs[inputPin]) {
                return {
                    node: node,
                    pin: inputPin
                };
            }
        }
    }
});

/* harmony default export */ const compositor_Graph = (Graph);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/Compositor.js




/**
 * Compositor provide graph based post processing
 *
 * @constructor clay.compositor.Compositor
 * @extends clay.compositor.Graph
 *
 */
var Compositor = compositor_Graph.extend(function() {
    return {
        // Output node
        _outputs: [],

        _texturePool: new compositor_TexturePool(),

        _frameBuffer: new src_FrameBuffer({
            depthBuffer: false
        })
    };
},
/** @lends clay.compositor.Compositor.prototype */
{
    addNode: function(node) {
        compositor_Graph.prototype.addNode.call(this, node);
        node._compositor = this;
    },
    /**
     * @param  {clay.Renderer} renderer
     */
    render: function(renderer, frameBuffer) {
        if (this._dirty) {
            this.update();
            this._dirty = false;

            this._outputs.length = 0;
            for (var i = 0; i < this.nodes.length; i++) {
                if (!this.nodes[i].outputs) {
                    this._outputs.push(this.nodes[i]);
                }
            }
        }

        for (var i = 0; i < this.nodes.length; i++) {
            // Update the reference number of each output texture
            this.nodes[i].beforeFrame();
        }

        for (var i = 0; i < this._outputs.length; i++) {
            this._outputs[i].updateReference();
        }

        for (var i = 0; i < this._outputs.length; i++) {
            this._outputs[i].render(renderer, frameBuffer);
        }

        for (var i = 0; i < this.nodes.length; i++) {
            // Clear up
            this.nodes[i].afterFrame();
        }
    },

    allocateTexture: function (parameters) {
        return this._texturePool.get(parameters);
    },

    releaseTexture: function (parameters) {
        this._texturePool.put(parameters);
    },

    getFrameBuffer: function () {
        return this._frameBuffer;
    },

    /**
     * Dispose compositor
     * @param {clay.Renderer} renderer
     */
    dispose: function (renderer) {
        this._texturePool.clear(renderer);
    }
});

/* harmony default export */ const compositor_Compositor = (Compositor);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/SceneNode.js




/**
 * @constructor clay.compositor.SceneNode
 * @extends clay.compositor.CompositorNode
 */
var SceneNode = compositor_CompositorNode.extend(
/** @lends clay.compositor.SceneNode# */
{
    name: 'scene',
    /**
     * @type {clay.Scene}
     */
    scene: null,
    /**
     * @type {clay.Camera}
     */
    camera: null,
    /**
     * @type {boolean}
     */
    autoUpdateScene: true,
    /**
     * @type {boolean}
     */
    preZ: false

}, function() {
    this.frameBuffer = new src_FrameBuffer();
}, {
    render: function(renderer) {

        this._rendering = true;
        var _gl = renderer.gl;

        this.trigger('beforerender');

        var renderInfo;

        if (!this.outputs) {

            renderInfo = renderer.render(this.scene, this.camera, !this.autoUpdateScene, this.preZ);

        }
        else {

            var frameBuffer = this.frameBuffer;
            for (var name in this.outputs) {
                var parameters = this.updateParameter(name, renderer);
                var outputInfo = this.outputs[name];
                var texture = this._compositor.allocateTexture(parameters);
                this._outputTextures[name] = texture;

                var attachment = outputInfo.attachment || _gl.COLOR_ATTACHMENT0;
                if (typeof(attachment) == 'string') {
                    attachment = _gl[attachment];
                }
                frameBuffer.attach(texture, attachment);
            }
            frameBuffer.bind(renderer);

            // MRT Support in chrome
            // https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/ext-draw-buffers.html
            var ext = renderer.getGLExtension('EXT_draw_buffers');
            if (ext) {
                var bufs = [];
                for (var attachment in this.outputs) {
                    attachment = parseInt(attachment);
                    if (attachment >= _gl.COLOR_ATTACHMENT0 && attachment <= _gl.COLOR_ATTACHMENT0 + 8) {
                        bufs.push(attachment);
                    }
                }
                ext.drawBuffersEXT(bufs);
            }

            // Always clear
            // PENDING
            renderer.saveClear();
            renderer.clearBit = glenum.DEPTH_BUFFER_BIT | glenum.COLOR_BUFFER_BIT;
            renderInfo = renderer.render(this.scene, this.camera, !this.autoUpdateScene, this.preZ);
            renderer.restoreClear();

            frameBuffer.unbind(renderer);
        }

        this.trigger('afterrender', renderInfo);

        this._rendering = false;
        this._rendered = true;
    }
});

/* harmony default export */ const compositor_SceneNode = (SceneNode);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/TextureNode.js


/**
 * @constructor clay.compositor.TextureNode
 * @extends clay.compositor.CompositorNode
 */
var TextureNode = compositor_CompositorNode.extend(function() {
    return /** @lends clay.compositor.TextureNode# */ {
        /**
         * @type {clay.Texture2D}
         */
        texture: null,

        // Texture node must have output without parameters
        outputs: {
            color: {}
        }
    };
}, function () {
}, {

    getOutput: function (renderer, name) {
        return this.texture;
    },

    // Do nothing
    beforeFrame: function () {},
    afterFrame: function () {}
});

/* harmony default export */ const compositor_TextureNode = (TextureNode);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/FilterNode.js
// TODO Shader library



// TODO curlnoise demo wrong

// PENDING
// Use topological sort ?

/**
 * Filter node
 *
 * @constructor clay.compositor.FilterNode
 * @extends clay.compositor.CompositorNode
 *
 * @example
    var node = new clay.compositor.FilterNode({
        name: 'fxaa',
        shader: clay.Shader.source('clay.compositor.fxaa'),
        inputs: {
            texture: {
                    node: 'scene',
                    pin: 'color'
            }
        },
        // Multiple outputs is preserved for MRT support in WebGL2.0
        outputs: {
            color: {
                attachment: clay.FrameBuffer.COLOR_ATTACHMENT0
                parameters: {
                    format: clay.Texture.RGBA,
                    width: 512,
                    height: 512
                },
                // Node will keep the RTT rendered in last frame
                keepLastFrame: true,
                // Force the node output the RTT rendered in last frame
                outputLastFrame: true
            }
        }
    });
    *
    */
var FilterNode = compositor_CompositorNode.extend(function () {
    return /** @lends clay.compositor.FilterNode# */ {
        /**
         * @type {string}
         */
        name: '',

        /**
         * @type {Object}
         */
        inputs: {},

        /**
         * @type {Object}
         */
        outputs: null,

        /**
         * @type {string}
         */
        shader: '',

        /**
         * Input links, will be updated by the graph
         * @example:
         *     inputName: {
         *         node: someNode,
         *         pin: 'xxxx'
         *     }
         * @type {Object}
         */
        inputLinks: {},

        /**
         * Output links, will be updated by the graph
         * @example:
         *     outputName: {
         *         node: someNode,
         *         pin: 'xxxx'
         *     }
         * @type {Object}
         */
        outputLinks: {},

        /**
         * @type {clay.compositor.Pass}
         */
        pass: null,

        // Save the output texture of previous frame
        // Will be used when there exist a circular reference
        _prevOutputTextures: {},
        _outputTextures: {},

        // Example: { name: 2 }
        _outputReferences: {},

        _rendering: false,
        // If rendered in this frame
        _rendered: false,

        _compositor: null
    };
}, function () {

    var pass = new compositor_Pass({
        fragment: this.shader
    });
    this.pass = pass;
},
/** @lends clay.compositor.FilterNode.prototype */
{
    /**
     * @param  {clay.Renderer} renderer
     */
    render: function (renderer, frameBuffer) {
        this.trigger('beforerender', renderer);

        this._rendering = true;

        var _gl = renderer.gl;

        for (var inputName in this.inputLinks) {
            var link = this.inputLinks[inputName];
            var inputTexture = link.node.getOutput(renderer, link.pin);
            this.pass.setUniform(inputName, inputTexture);
        }
        // Output
        if (!this.outputs) {
            this.pass.outputs = null;

            this._compositor.getFrameBuffer().unbind(renderer);

            this.pass.render(renderer, frameBuffer);
        }
        else {
            this.pass.outputs = {};

            var attachedTextures = {};
            for (var name in this.outputs) {
                var parameters = this.updateParameter(name, renderer);
                if (isNaN(parameters.width)) {
                    this.updateParameter(name, renderer);
                }
                var outputInfo = this.outputs[name];
                var texture = this._compositor.allocateTexture(parameters);
                this._outputTextures[name] = texture;
                var attachment = outputInfo.attachment || _gl.COLOR_ATTACHMENT0;
                if (typeof(attachment) === 'string') {
                    attachment = _gl[attachment];
                }
                attachedTextures[attachment] = texture;
            }
            this._compositor.getFrameBuffer().bind(renderer);

            for (var attachment in attachedTextures) {
                // FIXME attachment changes in different nodes
                this._compositor.getFrameBuffer().attach(
                    attachedTextures[attachment], attachment
                );
            }

            this.pass.render(renderer);

            // Because the data of texture is changed over time,
            // Here update the mipmaps of texture each time after rendered;
            this._compositor.getFrameBuffer().updateMipmap(renderer);
        }

        for (var inputName in this.inputLinks) {
            var link = this.inputLinks[inputName];
            link.node.removeReference(link.pin);
        }

        this._rendering = false;
        this._rendered = true;

        this.trigger('afterrender', renderer);
    },

    // TODO Remove parameter function callback
    updateParameter: function (outputName, renderer) {
        var outputInfo = this.outputs[outputName];
        var parameters = outputInfo.parameters;
        var parametersCopy = outputInfo._parametersCopy;
        if (!parametersCopy) {
            parametersCopy = outputInfo._parametersCopy = {};
        }
        if (parameters) {
            for (var key in parameters) {
                if (key !== 'width' && key !== 'height') {
                    parametersCopy[key] = parameters[key];
                }
            }
        }
        var width, height;
        if (typeof parameters.width === 'function') {
            width = parameters.width.call(this, renderer);
        }
        else {
            width = parameters.width;
        }
        if (typeof parameters.height === 'function') {
            height = parameters.height.call(this, renderer);
        }
        else {
            height = parameters.height;
        }
        width = Math.ceil(width);
        height = Math.ceil(height);
        if (
            parametersCopy.width !== width
            || parametersCopy.height !== height
        ) {
            if (this._outputTextures[outputName]) {
                this._outputTextures[outputName].dispose(renderer);
            }
        }
        parametersCopy.width = width;
        parametersCopy.height = height;

        return parametersCopy;
    },

    /**
     * Set parameter
     * @param {string} name
     * @param {} value
     */
    setParameter: function (name, value) {
        this.pass.setUniform(name, value);
    },
    /**
     * Get parameter value
     * @param  {string} name
     * @return {}
     */
    getParameter: function (name) {
        return this.pass.getUniform(name);
    },
    /**
     * Set parameters
     * @param {Object} obj
     */
    setParameters: function (obj) {
        for (var name in obj) {
            this.setParameter(name, obj[name]);
        }
    },
    // /**
    //  * Set shader code
    //  * @param {string} shaderStr
    //  */
    // setShader: function (shaderStr) {
    //     var material = this.pass.material;
    //     material.shader.setFragment(shaderStr);
    //     material.attachShader(material.shader, true);
    // },
    /**
     * Proxy of pass.material.define('fragment', xxx);
     * @param  {string} symbol
     * @param  {number} [val]
     */
    define: function (symbol, val) {
        this.pass.material.define('fragment', symbol, val);
    },

    /**
     * Proxy of pass.material.undefine('fragment', xxx)
     * @param  {string} symbol
     */
    undefine: function (symbol) {
        this.pass.material.undefine('fragment', symbol);
    },

    removeReference: function (outputName) {
        this._outputReferences[outputName]--;
        if (this._outputReferences[outputName] === 0) {
            var outputInfo = this.outputs[outputName];
            if (outputInfo.keepLastFrame) {
                if (this._prevOutputTextures[outputName]) {
                    this._compositor.releaseTexture(this._prevOutputTextures[outputName]);
                }
                this._prevOutputTextures[outputName] = this._outputTextures[outputName];
            }
            else {
                // Output of this node have alreay been used by all other nodes
                // Put the texture back to the pool.
                this._compositor.releaseTexture(this._outputTextures[outputName]);
            }
        }
    },

    clear: function () {
        compositor_CompositorNode.prototype.clear.call(this);

        // Default disable all texture
        this.pass.material.disableTexturesAll();
    }
});

/* harmony default export */ const compositor_FilterNode = (FilterNode);

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/coloradjust.glsl.js
/* harmony default export */ const coloradjust_glsl = ("@export clay.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/blur.glsl.js
/* harmony default export */ const blur_glsl = ("@export clay.compositor.kernel.gaussian_9\nfloat gaussianKernel[9];\ngaussianKernel[0] = 0.07;\ngaussianKernel[1] = 0.09;\ngaussianKernel[2] = 0.12;\ngaussianKernel[3] = 0.14;\ngaussianKernel[4] = 0.16;\ngaussianKernel[5] = 0.14;\ngaussianKernel[6] = 0.12;\ngaussianKernel[7] = 0.09;\ngaussianKernel[8] = 0.07;\n@end\n@export clay.compositor.kernel.gaussian_13\nfloat gaussianKernel[13];\ngaussianKernel[0] = 0.02;\ngaussianKernel[1] = 0.03;\ngaussianKernel[2] = 0.06;\ngaussianKernel[3] = 0.08;\ngaussianKernel[4] = 0.11;\ngaussianKernel[5] = 0.13;\ngaussianKernel[6] = 0.14;\ngaussianKernel[7] = 0.13;\ngaussianKernel[8] = 0.11;\ngaussianKernel[9] = 0.08;\ngaussianKernel[10] = 0.06;\ngaussianKernel[11] = 0.03;\ngaussianKernel[12] = 0.02;\n@end\n@export clay.compositor.gaussian_blur\n#define SHADER_NAME gaussian_blur\nuniform sampler2D texture;varying vec2 v_Texcoord;\nuniform float blurSize : 2.0;\nuniform vec2 textureSize : [512.0, 512.0];\nuniform float blurDir : 0.0;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main (void)\n{\n @import clay.compositor.kernel.gaussian_9\n vec2 off = blurSize / textureSize;\n off *= vec2(1.0 - blurDir, blurDir);\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n for (int i = 0; i < 9; i++) {\n float w = gaussianKernel[i];\n vec4 texel = decodeHDR(clampSample(texture, v_Texcoord + float(i - 4) * off));\n sum += texel * w;\n weightAll += w;\n }\n gl_FragColor = encodeHDR(sum / max(weightAll, 0.01));\n}\n@end\n");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/lum.glsl.js
/* harmony default export */ const lum_glsl = ("@export clay.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export clay.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import clay.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export clay.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/lut.glsl.js
/* harmony default export */ const lut_glsl = ("\n@export clay.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/vignette.glsl.js
/* harmony default export */ const vignette_glsl = ("@export clay.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/output.glsl.js
/* harmony default export */ const output_glsl = ("@export clay.compositor.output\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = tex.rgb;\n#ifdef OUTPUT_ALPHA\n gl_FragColor.a = tex.a;\n#else\n gl_FragColor.a = 1.0;\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/bright.glsl.js
/* harmony default export */ const bright_glsl = ("@export clay.compositor.bright\nuniform sampler2D texture;\nuniform float threshold : 1;\nuniform float scale : 1.0;\nuniform vec2 textureSize: [512, 512];\nvarying vec2 v_Texcoord;\nconst vec3 lumWeight = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvec4 median(vec4 a, vec4 b, vec4 c)\n{\n return a + b + c - min(min(a, b), c) - max(max(a, b), c);\n}\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n#ifdef ANTI_FLICKER\n vec3 d = 1.0 / textureSize.xyx * vec3(1.0, 1.0, 0.0);\n vec4 s1 = decodeHDR(texture2D(texture, v_Texcoord - d.xz));\n vec4 s2 = decodeHDR(texture2D(texture, v_Texcoord + d.xz));\n vec4 s3 = decodeHDR(texture2D(texture, v_Texcoord - d.zy));\n vec4 s4 = decodeHDR(texture2D(texture, v_Texcoord + d.zy));\n texel = median(median(texel, s1, s2), s3, s4);\n#endif\n float lum = dot(texel.rgb , lumWeight);\n vec4 color;\n if (lum > threshold && texel.a > 0.0)\n {\n color = vec4(texel.rgb * scale, texel.a * scale);\n }\n else\n {\n color = vec4(0.0);\n }\n gl_FragColor = encodeHDR(color);\n}\n@end\n");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/downsample.glsl.js
/* harmony default export */ const downsample_glsl = ("@export clay.compositor.downsample\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nfloat brightness(vec3 c)\n{\n return max(max(c.r, c.g), c.b);\n}\n@import clay.util.clamp_sample\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n#ifdef ANTI_FLICKER\n vec3 s1 = decodeHDR(clampSample(texture, v_Texcoord + d.xy)).rgb;\n vec3 s2 = decodeHDR(clampSample(texture, v_Texcoord + d.zy)).rgb;\n vec3 s3 = decodeHDR(clampSample(texture, v_Texcoord + d.xw)).rgb;\n vec3 s4 = decodeHDR(clampSample(texture, v_Texcoord + d.zw)).rgb;\n float s1w = 1.0 / (brightness(s1) + 1.0);\n float s2w = 1.0 / (brightness(s2) + 1.0);\n float s3w = 1.0 / (brightness(s3) + 1.0);\n float s4w = 1.0 / (brightness(s4) + 1.0);\n float oneDivideSum = 1.0 / (s1w + s2w + s3w + s4w);\n vec4 color = vec4(\n (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * oneDivideSum,\n 1.0\n );\n#else\n vec4 color = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n color *= 0.25;\n#endif\n gl_FragColor = encodeHDR(color);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/upsample.glsl.js
/* harmony default export */ const upsample_glsl = ("\n@export clay.compositor.upsample\n#define HIGH_QUALITY\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord - d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord - d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord - d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord )) * 4.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n gl_FragColor = encodeHDR(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n gl_FragColor = encodeHDR(s / 4.0);\n#endif\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/hdr.glsl.js
/* harmony default export */ const hdr_glsl = ("@export clay.compositor.hdr.composite\n#define TONEMAPPING\nuniform sampler2D texture;\n#ifdef BLOOM_ENABLED\nuniform sampler2D bloom;\n#endif\n#ifdef LENSFLARE_ENABLED\nuniform sampler2D lensflare;\nuniform sampler2D lensdirt;\n#endif\n#ifdef LUM_ENABLED\nuniform sampler2D lum;\n#endif\n#ifdef LUT_ENABLED\nuniform sampler2D lut;\n#endif\n#ifdef COLOR_CORRECTION\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float saturation : 1.0;\n#endif\n#ifdef VIGNETTE\nuniform float vignetteDarkness: 1.0;\nuniform float vignetteOffset: 1.0;\n#endif\nuniform float exposure : 1.0;\nuniform float bloomIntensity : 0.25;\nuniform float lensflareIntensity : 1;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nfloat eyeAdaption(float fLum)\n{\n return mix(0.2, fLum, 0.5);\n}\n#ifdef LUT_ENABLED\nvec3 lutTransform(vec3 color) {\n float blueColor = color.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec4 newColor1 = texture2D(lut, texPos1);\n vec4 newColor2 = texture2D(lut, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n return newColor.rgb;\n}\n#endif\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = vec4(0.0);\n vec4 originalTexel = vec4(0.0);\n#ifdef TEXTURE_ENABLED\n texel = decodeHDR(texture2D(texture, v_Texcoord));\n originalTexel = texel;\n#endif\n#ifdef BLOOM_ENABLED\n vec4 bloomTexel = decodeHDR(texture2D(bloom, v_Texcoord));\n texel.rgb += bloomTexel.rgb * bloomIntensity;\n texel.a += bloomTexel.a * bloomIntensity;\n#endif\n#ifdef LENSFLARE_ENABLED\n texel += decodeHDR(texture2D(lensflare, v_Texcoord)) * texture2D(lensdirt, v_Texcoord) * lensflareIntensity;\n#endif\n texel.a = min(texel.a, 1.0);\n#ifdef LUM_ENABLED\n float fLum = texture2D(lum, vec2(0.5, 0.5)).r;\n float adaptedLumDest = 3.0 / (max(0.1, 1.0 + 10.0*eyeAdaption(fLum)));\n float exposureBias = adaptedLumDest * exposure;\n#else\n float exposureBias = exposure;\n#endif\n#ifdef TONEMAPPING\n texel.rgb *= exposureBias;\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n texel = linearTosRGB(texel);\n#ifdef LUT_ENABLED\n texel.rgb = lutTransform(clamp(texel.rgb,vec3(0.0),vec3(1.0)));\n#endif\n#ifdef COLOR_CORRECTION\n texel.rgb = clamp(texel.rgb + vec3(brightness), 0.0, 1.0);\n texel.rgb = clamp((texel.rgb - vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n float lum = dot(texel.rgb, vec3(0.2125, 0.7154, 0.0721));\n texel.rgb = mix(vec3(lum), texel.rgb, saturation);\n#endif\n#ifdef VIGNETTE\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(vignetteOffset);\n texel.rgb = mix(texel.rgb, vec3(1.0 - vignetteDarkness), dot(uv, uv));\n#endif\n gl_FragColor = encodeHDR(texel);\n#ifdef DEBUG\n #if DEBUG == 1\n gl_FragColor = encodeHDR(decodeHDR(texture2D(texture, v_Texcoord)));\n #elif DEBUG == 2\n gl_FragColor = encodeHDR(decodeHDR(texture2D(bloom, v_Texcoord)) * bloomIntensity);\n #elif DEBUG == 3\n gl_FragColor = encodeHDR(decodeHDR(texture2D(lensflare, v_Texcoord) * lensflareIntensity));\n #endif\n#endif\n if (originalTexel.a <= 0.01 && gl_FragColor.a > 1e-5) {\n gl_FragColor.a = dot(gl_FragColor.rgb, vec3(0.2125, 0.7154, 0.0721));\n }\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/lensflare.glsl.js
/* harmony default export */ const lensflare_glsl = ("@export clay.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/blend.glsl.js
/* harmony default export */ const blend_glsl = ("@export clay.compositor.blend\n#define SHADER_NAME blend\n#ifdef TEXTURE1_ENABLED\nuniform sampler2D texture1;\nuniform float weight1 : 1.0;\n#endif\n#ifdef TEXTURE2_ENABLED\nuniform sampler2D texture2;\nuniform float weight2 : 1.0;\n#endif\n#ifdef TEXTURE3_ENABLED\nuniform sampler2D texture3;\nuniform float weight3 : 1.0;\n#endif\n#ifdef TEXTURE4_ENABLED\nuniform sampler2D texture4;\nuniform float weight4 : 1.0;\n#endif\n#ifdef TEXTURE5_ENABLED\nuniform sampler2D texture5;\nuniform float weight5 : 1.0;\n#endif\n#ifdef TEXTURE6_ENABLED\nuniform sampler2D texture6;\nuniform float weight6 : 1.0;\n#endif\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = vec4(0.0);\n#ifdef TEXTURE1_ENABLED\n tex += decodeHDR(texture2D(texture1, v_Texcoord)) * weight1;\n#endif\n#ifdef TEXTURE2_ENABLED\n tex += decodeHDR(texture2D(texture2, v_Texcoord)) * weight2;\n#endif\n#ifdef TEXTURE3_ENABLED\n tex += decodeHDR(texture2D(texture3, v_Texcoord)) * weight3;\n#endif\n#ifdef TEXTURE4_ENABLED\n tex += decodeHDR(texture2D(texture4, v_Texcoord)) * weight4;\n#endif\n#ifdef TEXTURE5_ENABLED\n tex += decodeHDR(texture2D(texture5, v_Texcoord)) * weight5;\n#endif\n#ifdef TEXTURE6_ENABLED\n tex += decodeHDR(texture2D(texture6, v_Texcoord)) * weight6;\n#endif\n gl_FragColor = encodeHDR(tex);\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/source/compositor/fxaa.glsl.js
/* harmony default export */ const fxaa_glsl = ("@export clay.compositor.fxaa\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nvarying vec2 v_Texcoord;\n#define FXAA_REDUCE_MIN (1.0/128.0)\n#define FXAA_REDUCE_MUL (1.0/8.0)\n#define FXAA_SPAN_MAX 8.0\n@import clay.util.rgbm\nvoid main()\n{\n vec2 resolution = 1.0 / viewport.zw;\n vec3 rgbNW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbNE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ) ).xyz;\n vec4 rgbaM = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution ) );\n vec3 rgbM = rgbaM.xyz;\n float opacity = rgbaM.w;\n vec3 luma = vec3( 0.299, 0.587, 0.114 );\n float lumaNW = dot( rgbNW, luma );\n float lumaNE = dot( rgbNE, luma );\n float lumaSW = dot( rgbSW, luma );\n float lumaSE = dot( rgbSE, luma );\n float lumaM = dot( rgbM, luma );\n float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );\n float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );\n vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );\n float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );\n dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * resolution;\n vec3 rgbA = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA *= 0.5;\n vec3 rgbB = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * -0.5 ) ).xyz;\n rgbB += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * 0.5 ) ).xyz;\n rgbB *= 0.25;\n rgbB += rgbA * 0.5;\n float lumaB = dot( rgbB, luma );\n if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )\n {\n gl_FragColor = vec4( rgbA, opacity );\n }\n else {\n gl_FragColor = vec4( rgbB, opacity );\n }\n}\n@end");

;// CONCATENATED MODULE: ./node_modules/claygl/src/shader/registerBuiltinCompositor.js













// import fxaa3Essl from './source/compositor/fxaa3.glsl.js';

// TODO Must export a module and be used in the other modules. Or it will be tree shaked
function register(Shader) {
    // Some build in shaders
    Shader['import'](coloradjust_glsl);
    Shader['import'](blur_glsl);
    Shader['import'](lum_glsl);
    Shader['import'](lut_glsl);
    Shader['import'](vignette_glsl);
    Shader['import'](output_glsl);
    Shader['import'](bright_glsl);
    Shader['import'](downsample_glsl);
    Shader['import'](upsample_glsl);
    Shader['import'](hdr_glsl);
    Shader['import'](lensflare_glsl);
    Shader['import'](blend_glsl);

    Shader['import'](fxaa_glsl);

}
;// CONCATENATED MODULE: ./node_modules/claygl/src/createCompositor.js












register(src_Shader);

var shaderSourceReg = /^#source\((.*?)\)/;

/**
 * @name clay.createCompositor
 * @function
 * @param {Object} json
 * @param {Object} [opts]
 * @return {clay.compositor.Compositor}
 */
function createCompositor(json, opts) {
    var compositor = new compositor_Compositor();
    opts = opts || {};

    var lib = {
        textures: {},
        parameters: {}
    };
    var afterLoad = function(shaderLib, textureLib) {
        for (var i = 0; i < json.nodes.length; i++) {
            var nodeInfo = json.nodes[i];
            var node = createNode(nodeInfo, lib, opts);
            if (node) {
                compositor.addNode(node);
            }
        }
    };

    for (var name in json.parameters) {
        var paramInfo = json.parameters[name];
        lib.parameters[name] = convertParameter(paramInfo);
    }
    // TODO load texture asynchronous
    loadTextures(json, lib, opts, function(textureLib) {
        lib.textures = textureLib;
        afterLoad();
    });

    return compositor;
}

function createNode(nodeInfo, lib, opts) {
    var type = nodeInfo.type || 'filter';
    var shaderSource;
    var inputs;
    var outputs;

    if (type === 'filter') {
        var shaderExp = nodeInfo.shader.trim();
        var res = shaderSourceReg.exec(shaderExp);
        if (res) {
            shaderSource = src_Shader.source(res[1].trim());
        }
        else if (shaderExp.charAt(0) === '#') {
            shaderSource = lib.shaders[shaderExp.substr(1)];
        }
        if (!shaderSource) {
            shaderSource = shaderExp;
        }
        if (!shaderSource) {
            return;
        }
    }

    if (nodeInfo.inputs) {
        inputs = {};
        for (var name in nodeInfo.inputs) {
            if (typeof nodeInfo.inputs[name] === 'string') {
                inputs[name] = nodeInfo.inputs[name];
            }
            else {
                inputs[name] = {
                    node: nodeInfo.inputs[name].node,
                    pin: nodeInfo.inputs[name].pin
                };
            }
        }
    }
    if (nodeInfo.outputs) {
        outputs = {};
        for (var name in nodeInfo.outputs) {
            var outputInfo = nodeInfo.outputs[name];
            outputs[name] = {};
            if (outputInfo.attachment != null) {
                outputs[name].attachment = outputInfo.attachment;
            }
            if (outputInfo.keepLastFrame != null) {
                outputs[name].keepLastFrame = outputInfo.keepLastFrame;
            }
            if (outputInfo.outputLastFrame != null) {
                outputs[name].outputLastFrame = outputInfo.outputLastFrame;
            }
            if (outputInfo.parameters) {
                outputs[name].parameters = convertParameter(outputInfo.parameters);
            }
        }
    }
    var node;
    if (type === 'scene') {
        node = new compositor_SceneNode({
            name: nodeInfo.name,
            scene: opts.scene,
            camera: opts.camera,
            outputs: outputs
        });
    }
    else if (type === 'texture') {
        node = new compositor_TextureNode({
            name: nodeInfo.name,
            outputs: outputs
        });
    }
    // Default is filter
    else {
        node = new compositor_FilterNode({
            name: nodeInfo.name,
            shader: shaderSource,
            inputs: inputs,
            outputs: outputs
        });
    }
    if (node) {
        if (nodeInfo.parameters) {
            for (var name in nodeInfo.parameters) {
                var val = nodeInfo.parameters[name];
                if (typeof val === 'string') {
                    val = val.trim();
                    if (val.charAt(0) === '#') {
                        val = lib.textures[val.substr(1)];
                    }
                    else {
                        node.on(
                            'beforerender', createSizeSetHandler(
                                name, tryConvertExpr(val)
                            )
                        );
                    }
                }
                else if (typeof val === 'function') {
                    node.on('beforerender', val);
                }
                node.setParameter(name, val);
            }
        }
        if (nodeInfo.defines && node.pass) {
            for (var name in nodeInfo.defines) {
                var val = nodeInfo.defines[name];
                node.pass.material.define('fragment', name, val);
            }
        }
    }
    return node;
}

function defaultWidthFunc(width, height) {
    return width;
}
function defaultHeightFunc(width, height) {
    return height;
}

function convertParameter(paramInfo) {
    var param = {};
    if (!paramInfo) {
        return param;
    }
    ['type', 'minFilter', 'magFilter', 'wrapS', 'wrapT', 'flipY', 'useMipmap']
        .forEach(function(name) {
            var val = paramInfo[name];
            if (val != null) {
                // Convert string to enum
                if (typeof val === 'string') {
                    val = src_Texture[val];
                }
                param[name] = val;
            }
        });

    var sizeScale = paramInfo.scale || 1;
    ['width', 'height']
        .forEach(function(name) {
            if (paramInfo[name] != null) {
                var val = paramInfo[name];
                if (typeof val === 'string') {
                    val = val.trim();
                    param[name] = createSizeParser(
                        name, tryConvertExpr(val), sizeScale
                    );
                }
                else {
                    param[name] = val;
                }
            }
        });
    if (!param.width) {
        param.width = defaultWidthFunc;
    }
    if (!param.height) {
        param.height = defaultHeightFunc;
    }

    if (paramInfo.useMipmap != null) {
        param.useMipmap = paramInfo.useMipmap;
    }
    return param;
}

function loadTextures(json, lib, opts, callback) {
    if (!json.textures) {
        callback({});
        return;
    }
    var textures = {};
    var loading = 0;

    var cbd = false;
    var textureRootPath = opts.textureRootPath;
    core_util.each(json.textures, function(textureInfo, name) {
        var texture;
        var path = textureInfo.path;
        var parameters = convertParameter(textureInfo.parameters);
        if (Array.isArray(path) && path.length === 6) {
            if (textureRootPath) {
                path = path.map(function(item) {
                    return core_util.relative2absolute(item, textureRootPath);
                });
            }
            texture = new src_TextureCube(parameters);
        }
        else if(typeof path === 'string') {
            if (textureRootPath) {
                path = core_util.relative2absolute(path, textureRootPath);
            }
            texture = new src_Texture2D(parameters);
        }
        else {
            return;
        }

        texture.load(path);
        loading++;
        texture.once('success', function() {
            textures[name] = texture;
            loading--;
            if (loading === 0) {
                callback(textures);
                cbd = true;
            }
        });
    });

    if (loading === 0 && !cbd) {
        callback(textures);
    }
}

function createSizeSetHandler(name, exprFunc) {
    return function (renderer) {
        // PENDING viewport size or window size
        var dpr = renderer.getDevicePixelRatio();
        // PENDING If multiply dpr ?
        var width = renderer.getWidth();
        var height = renderer.getHeight();
        var result = exprFunc(width, height, dpr);
        this.setParameter(name, result);
    };
}

function createSizeParser(name, exprFunc, scale) {
    scale = scale || 1;
    return function (renderer) {
        var dpr = renderer.getDevicePixelRatio();
        var width = renderer.getWidth() * scale;
        var height = renderer.getHeight() * scale;
        return exprFunc(width, height, dpr);
    };
}

function tryConvertExpr(string) {
    // PENDING
    var exprRes = /^expr\((.*)\)$/.exec(string);
    if (exprRes) {
        try {
            var func = new Function('width', 'height', 'dpr', 'return ' + exprRes[1]);
            // Try run t
            func(1, 1);

            return func;
        }
        catch (e) {
            throw new Error('Invalid expression.');
        }
    }
}

/* harmony default export */ const src_createCompositor = (createCompositor);

;// CONCATENATED MODULE: ./node_modules/claygl/src/compositor/createCompositor.js
// DEPRECATED

/* harmony default export */ const compositor_createCompositor = (src_createCompositor);
;// CONCATENATED MODULE: ./src/effect/halton.js

// Generate halton sequence
// https://en.wikipedia.org/wiki/Halton_sequence
function halton(index, base) {

    var result = 0;
    var f = 1 / base;
    var i = index;
    while (i > 0) {
        result = result + f * (i % base);
        i = Math.floor(i / base);
        f = f / base;
    }
    return result;
}


/* harmony default export */ const effect_halton = (halton);
;// CONCATENATED MODULE: ./src/effect/SSAO.glsl.js
/* harmony default export */ const SSAO_glsl = ("@export ecgl.ssao.estimate\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 1e-2;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy * 0.5 + 0.5);\n\n float sampleDepth = depthTexel.r * 2.0 - 1.0;\n if (projection[3][3] == 0.0) {\n sampleDepth = projection[3][2] / (sampleDepth * projection[2][3] - projection[2][2]);\n }\n else {\n sampleDepth = (sampleDepth - projection[3][2]) / projection[2][2];\n }\n \n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - sampleDepth));\n occlusion += rangeCheck * step(samplePos.z, sampleDepth - bias);\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.5;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n float kernel[5];\n kernel[0] = 0.122581;\n kernel[1] = 0.233062;\n kernel[2] = 0.288713;\n kernel[3] = 0.233062;\n kernel[4] = 0.122581;\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 5; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 2.0) * off, vec2(0.0), vec2(1.0));\n\n float w = kernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n\n@end\n");

;// CONCATENATED MODULE: ./src/effect/SSAOPass.js










src_Shader.import(SSAO_glsl);

function generateNoiseData(size) {
    var data = new Uint8Array(size * size * 4);
    var n = 0;
    var v3 = new math_Vector3();

    for (var i = 0; i < size; i++) {
        for (var j = 0; j < size; j++) {
            v3.set(Math.random() * 2 - 1, Math.random() * 2 - 1, 0).normalize();
            data[n++] = (v3.x * 0.5 + 0.5) * 255;
            data[n++] = (v3.y * 0.5 + 0.5) * 255;
            data[n++] = 0;
            data[n++] = 255;
        }
    }
    return data;
}

function generateNoiseTexture(size) {
    return new src_Texture2D({
        pixels: generateNoiseData(size),
        wrapS: src_Texture.REPEAT,
        wrapT: src_Texture.REPEAT,
        width: size,
        height: size
    });
}

function generateKernel(size, offset, hemisphere) {
    var kernel = new Float32Array(size * 3);
    offset = offset || 0;
    for (var i = 0; i < size; i++) {
        var phi = effect_halton(i + offset, 2) * (hemisphere ? 1 : 2) * Math.PI;
        var theta = effect_halton(i + offset, 3) * Math.PI;
        var r = Math.random();
        var x = Math.cos(phi) * Math.sin(theta) * r;
        var y = Math.cos(theta) * r;
        var z = Math.sin(phi) * Math.sin(theta) * r;

        kernel[i * 3] = x;
        kernel[i * 3 + 1] = y;
        kernel[i * 3 + 2] = z;
    }
    return kernel;

    // var kernel = new Float32Array(size * 3);
    // var v3 = new Vector3();
    // for (var i = 0; i < size; i++) {
    //     v3.set(Math.random() * 2 - 1, Math.random() * 2 - 1, Math.random())
    //         .normalize().scale(Math.random());
    //     kernel[i * 3] = v3.x;
    //     kernel[i * 3 + 1] = v3.y;
    //     kernel[i * 3 + 2] = v3.z;
    // }
    // return kernel;
}

function SSAOPass(opt) {
    opt = opt || {};

    this._ssaoPass = new compositor_Pass({
        fragment: src_Shader.source('ecgl.ssao.estimate')
    });
    this._blurPass = new compositor_Pass({
        fragment: src_Shader.source('ecgl.ssao.blur')
    });
    this._framebuffer = new src_FrameBuffer({
        depthBuffer: false
    });

    this._ssaoTexture = new src_Texture2D();
    this._blurTexture = new src_Texture2D();
    this._blurTexture2 = new src_Texture2D();

    this._depthTex = opt.depthTexture;
    this._normalTex = opt.normalTexture;

    this.setNoiseSize(4);
    this.setKernelSize(opt.kernelSize || 12);
    if (opt.radius != null) {
        this.setParameter('radius', opt.radius);
    }
    if (opt.power != null) {
        this.setParameter('power', opt.power);
    }

    if (!this._normalTex) {
        this._ssaoPass.material.disableTexture('normalTex');
        this._blurPass.material.disableTexture('normalTex');
    }
    if (!this._depthTex) {
        this._blurPass.material.disableTexture('depthTex');
    }

    this._blurPass.material.setUniform('normalTex', this._normalTex);
    this._blurPass.material.setUniform('depthTex', this._depthTex);
}

SSAOPass.prototype.setDepthTexture = function (depthTex) {
    this._depthTex = depthTex;
};

SSAOPass.prototype.setNormalTexture = function (normalTex) {
    this._normalTex = normalTex;
    this._ssaoPass.material[normalTex ? 'enableTexture' : 'disableTexture']('normalTex');
    // Switch between hemisphere and shere kernel.
    this.setKernelSize(this._kernelSize);
};

SSAOPass.prototype.update = function (renderer, camera, frame) {
    var width = renderer.getWidth();
    var height = renderer.getHeight();

    var ssaoPass = this._ssaoPass;
    var blurPass = this._blurPass;

    ssaoPass.setUniform('kernel', this._kernels[frame % this._kernels.length]);
    ssaoPass.setUniform('depthTex', this._depthTex);
    if (this._normalTex != null) {
        ssaoPass.setUniform('normalTex', this._normalTex);
    }
    ssaoPass.setUniform('depthTexSize', [this._depthTex.width, this._depthTex.height]);

    var viewInverseTranspose = new math_Matrix4();
    math_Matrix4.transpose(viewInverseTranspose, camera.worldTransform);

    ssaoPass.setUniform('projection', camera.projectionMatrix.array);
    ssaoPass.setUniform('projectionInv', camera.invProjectionMatrix.array);
    ssaoPass.setUniform('viewInverseTranspose', viewInverseTranspose.array);

    var ssaoTexture = this._ssaoTexture;
    var blurTexture = this._blurTexture;
    var blurTexture2 = this._blurTexture2;

    ssaoTexture.width = width / 2;
    ssaoTexture.height = height / 2;
    blurTexture.width = width;
    blurTexture.height = height;
    blurTexture2.width = width;
    blurTexture2.height = height;

    this._framebuffer.attach(ssaoTexture);
    this._framebuffer.bind(renderer);
    renderer.gl.clearColor(1, 1, 1, 1);
    renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT);
    ssaoPass.render(renderer);

    blurPass.setUniform('textureSize', [width / 2, height / 2]);
    blurPass.setUniform('projection', camera.projectionMatrix.array);
    this._framebuffer.attach(blurTexture);
    blurPass.setUniform('direction', 0);
    blurPass.setUniform('ssaoTexture', ssaoTexture);
    blurPass.render(renderer);

    this._framebuffer.attach(blurTexture2);
    blurPass.setUniform('textureSize', [width, height]);
    blurPass.setUniform('direction', 1);
    blurPass.setUniform('ssaoTexture', blurTexture);
    blurPass.render(renderer);

    this._framebuffer.unbind(renderer);

    // Restore clear
    var clearColor = renderer.clearColor;
    renderer.gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
};

SSAOPass.prototype.getTargetTexture = function () {
    return this._blurTexture2;
}

SSAOPass.prototype.setParameter = function (name, val) {
    if (name === 'noiseTexSize') {
        this.setNoiseSize(val);
    }
    else if (name === 'kernelSize') {
        this.setKernelSize(val);
    }
    else if (name === 'intensity') {
        this._ssaoPass.material.set('intensity', val);
    }
    else {
        this._ssaoPass.setUniform(name, val);
    }
};

SSAOPass.prototype.setKernelSize = function (size) {
    this._kernelSize = size;
    this._ssaoPass.material.define('fragment', 'KERNEL_SIZE', size);
    this._kernels = this._kernels || [];
    for (var i = 0; i < 30; i++) {
        this._kernels[i] = generateKernel(size, i * size, !!this._normalTex);
    }
};

SSAOPass.prototype.setNoiseSize = function (size) {
    var texture = this._ssaoPass.getUniform('noiseTex');
    if (!texture) {
        texture = generateNoiseTexture(size);
        this._ssaoPass.setUniform('noiseTex', generateNoiseTexture(size));
    }
    else {
        texture.data = generateNoiseData(size);
        texture.width = texture.height = size;
        texture.dirty();
    }

    this._ssaoPass.setUniform('noiseTexSize', [size, size]);
};

SSAOPass.prototype.dispose = function (renderer) {
    this._blurTexture.dispose(renderer);
    this._ssaoTexture.dispose(renderer);
    this._blurTexture2.dispose(renderer);
};

/* harmony default export */ const effect_SSAOPass = (SSAOPass);
;// CONCATENATED MODULE: ./src/effect/SSR.glsl.js
/* harmony default export */ const SSR_glsl = ("@export ecgl.ssr.main\n\n#define SHADER_NAME SSR\n#define MAX_ITERATION 20;\n#define SAMPLE_PER_FRAME 5;\n#define TOTAL_SAMPLES 128;\n\nuniform sampler2D sourceTexture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform samplerCube specularCubemap;\nuniform float specularIntensity: 1;\n\nuniform mat4 projection;\nuniform mat4 projectionInv;\nuniform mat4 toViewSpace;\nuniform mat4 toWorldSpace;\n\nuniform float maxRayDistance: 200;\n\nuniform float pixelStride: 16;\nuniform float pixelStrideZCutoff: 50; \nuniform float screenEdgeFadeStart: 0.9; \nuniform float eyeFadeStart : 0.2; uniform float eyeFadeEnd: 0.8; \nuniform float minGlossiness: 0.2; uniform float zThicknessThreshold: 1;\n\nuniform float nearZ;\nuniform vec2 viewportSize : VIEWPORT_SIZE;\n\nuniform float jitterOffset: 0;\n\nvarying vec2 v_Texcoord;\n\n#ifdef DEPTH_DECODE\n@import clay.util.decode_float\n#endif\n\n#ifdef PHYSICALLY_CORRECT\nuniform sampler2D normalDistribution;\nuniform float sampleOffset: 0;\nuniform vec2 normalDistributionSize;\n\nvec3 transformNormal(vec3 H, vec3 N) {\n vec3 upVector = N.y > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvec3 importanceSampleNormalGGX(float i, float roughness, vec3 N) {\n float p = fract((i + sampleOffset) / float(TOTAL_SAMPLES));\n vec3 H = texture2D(normalDistribution,vec2(roughness, p)).rgb;\n return transformNormal(H, N);\n}\nfloat G_Smith(float g, float ndv, float ndl) {\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n dPQK *= 1.2;\n\n if (intersect) {\n break;\n }\n }\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import clay.util.rand\n\n@import clay.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n#if !defined(PHYSICALLY_CORRECT)\n if (g <= minGlossiness) {\n discard;\n }\n#endif\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalize(normalAndGloss.rgb * 2.0 - 1.0);\n N = normalize((toViewSpace * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n vec3 V = -normalize(rayOrigin);\n\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n float iterationCount;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n#ifdef PHYSICALLY_CORRECT\n vec4 color = vec4(vec3(0.0), 1.0);\n vec4 albedoMetalness = texture2D(gBufferTexture3, v_Texcoord);\n vec3 albedo = albedoMetalness.rgb;\n float m = albedoMetalness.a;\n vec3 diffuseColor = albedo * (1.0 - m);\n vec3 spec = mix(vec3(0.04), albedo, m);\n\n float jitter2 = rand(fract(v_Texcoord)) * float(TOTAL_SAMPLES);\n\n for (int i = 0; i < SAMPLE_PER_FRAME; i++) {\n vec3 H = importanceSampleNormalGGX(float(i) + jitter2, 1.0 - g, N);\n vec3 rayDir = normalize(reflect(-V, H));\n#else\n vec3 rayDir = normalize(reflect(-V, N));\n#endif\n vec2 hitPixel;\n vec3 hitPoint;\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((toViewSpace * vec4(hitNormal, 0.0)).xyz);\n#ifdef PHYSICALLY_CORRECT\n float ndl = clamp(dot(N, rayDir), 0.0, 1.0);\n float vdh = clamp(dot(V, H), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n vec3 litTexel = vec3(0.0);\n if (dot(hitNormal, rayDir) < 0.0 && intersect) {\n litTexel = texture2D(sourceTexture, hitPixel).rgb;\n litTexel *= pow(clamp(1.0 - dist / 200.0, 0.0, 1.0), 3.0);\n\n }\n else {\n #ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n litTexel = RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, 0.0), 8.12).rgb * specularIntensity;\n#endif\n }\n color.rgb += ndl * litTexel * (\n F_Schlick(ndl, spec) * G_Smith(g, ndv, ndl) * vdh / (ndh * ndv + 0.001)\n );\n }\n color.rgb /= float(SAMPLE_PER_FRAME);\n#else\n #if !defined(SPECULARCUBEMAP_ENABLED)\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n if (!intersect) {\n discard;\n }\n#endif\n float alpha = clamp(calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir), 0.0, 1.0);\n vec4 color = texture2D(sourceTexture, hitPixel);\n color.rgb *= alpha;\n\n#ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n alpha = alpha * (intersect ? 1.0 : 0.0);\n float bias = (1.0 -g) * 5.0;\n color.rgb += (1.0 - alpha)\n * RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, bias), 8.12).rgb\n * specularIntensity;\n#endif\n\n#endif\n\n gl_FragColor = encodeHDR(color);\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(gBufferTexture2, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n\n@import clay.util.rgbm\n\n\nvoid main()\n{\n @import clay.compositor.kernel.gaussian_9\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, maxBlurSize / textureSize.y);\n#else\n vec2 off = vec2(maxBlurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n float cD = getLinearDepth(v_Texcoord);\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp((float(i) - 4.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i]\n * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(cD - d) / depthRange, 0.0, 1.0));\n\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end");

;// CONCATENATED MODULE: ./src/effect/SSRPass.js












src_Shader.import(SSR_glsl);

function SSRPass(opt) {
    opt = opt || {};

    this._ssrPass = new compositor_Pass({
        fragment: src_Shader.source('ecgl.ssr.main'),
        clearColor: [0, 0, 0, 0]
    });
    this._blurPass1 = new compositor_Pass({
        fragment: src_Shader.source('ecgl.ssr.blur'),
        clearColor: [0, 0, 0, 0]
    });
    this._blurPass2 = new compositor_Pass({
        fragment: src_Shader.source('ecgl.ssr.blur'),
        clearColor: [0, 0, 0, 0]
    });
    this._blendPass = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.blend')
    });
    this._blendPass.material.disableTexturesAll();
    this._blendPass.material.enableTexture(['texture1', 'texture2']);

    this._ssrPass.setUniform('gBufferTexture1', opt.normalTexture);
    this._ssrPass.setUniform('gBufferTexture2', opt.depthTexture);
    // this._ssrPass.setUniform('gBufferTexture3', opt.albedoTexture);

    this._blurPass1.setUniform('gBufferTexture1', opt.normalTexture);
    this._blurPass1.setUniform('gBufferTexture2', opt.depthTexture);

    this._blurPass2.setUniform('gBufferTexture1', opt.normalTexture);
    this._blurPass2.setUniform('gBufferTexture2', opt.depthTexture);

    this._blurPass2.material.define('fragment', 'VERTICAL');
    this._blurPass2.material.define('fragment', 'BLEND');

    this._ssrTexture = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });
    this._texture2 = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });
    this._texture3 = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });
    this._prevTexture = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });
    this._currentTexture = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });

    this._frameBuffer = new src_FrameBuffer({
        depthBuffer: false
    });

    this._normalDistribution = null;

    this._totalSamples = 256;
    this._samplePerFrame = 4;

    this._ssrPass.material.define('fragment', 'SAMPLE_PER_FRAME', this._samplePerFrame);
    this._ssrPass.material.define('fragment', 'TOTAL_SAMPLES', this._totalSamples);

    this._downScale = 1;
}

SSRPass.prototype.setAmbientCubemap = function (specularCubemap, specularIntensity) {
    this._ssrPass.material.set('specularCubemap', specularCubemap);
    this._ssrPass.material.set('specularIntensity', specularIntensity);

    var enableSpecularMap = specularCubemap && specularIntensity;
    this._ssrPass.material[enableSpecularMap ? 'enableTexture' : 'disableTexture']('specularCubemap');
};

SSRPass.prototype.update = function (renderer, camera, sourceTexture, frame) {
    var width = renderer.getWidth();
    var height = renderer.getHeight();
    var ssrTexture = this._ssrTexture;
    var texture2 = this._texture2;
    var texture3 = this._texture3;
    ssrTexture.width = this._prevTexture.width = this._currentTexture.width = width / this._downScale;
    ssrTexture.height = this._prevTexture.height = this._currentTexture.height = height / this._downScale;

    texture2.width = texture3.width = width;
    texture2.height = texture3.height = height;

    var frameBuffer = this._frameBuffer;

    var ssrPass = this._ssrPass;
    var blurPass1 = this._blurPass1;
    var blurPass2 = this._blurPass2;
    var blendPass = this._blendPass;

    var toViewSpace = new math_Matrix4();
    var toWorldSpace = new math_Matrix4();
    math_Matrix4.transpose(toViewSpace, camera.worldTransform);
    math_Matrix4.transpose(toWorldSpace, camera.viewMatrix);

    ssrPass.setUniform('sourceTexture', sourceTexture);
    ssrPass.setUniform('projection', camera.projectionMatrix.array);
    ssrPass.setUniform('projectionInv', camera.invProjectionMatrix.array);
    ssrPass.setUniform('toViewSpace', toViewSpace.array);
    ssrPass.setUniform('toWorldSpace', toWorldSpace.array);
    ssrPass.setUniform('nearZ', camera.near);

    var percent = frame / this._totalSamples * this._samplePerFrame;
    ssrPass.setUniform('jitterOffset', percent);
    ssrPass.setUniform('sampleOffset', frame * this._samplePerFrame);

    blurPass1.setUniform('textureSize', [ssrTexture.width, ssrTexture.height]);
    blurPass2.setUniform('textureSize', [width, height]);
    blurPass2.setUniform('sourceTexture', sourceTexture);

    blurPass1.setUniform('projection', camera.projectionMatrix.array);
    blurPass2.setUniform('projection', camera.projectionMatrix.array);

    frameBuffer.attach(ssrTexture);
    frameBuffer.bind(renderer);
    ssrPass.render(renderer);

    if (this._physicallyCorrect) {
        frameBuffer.attach(this._currentTexture);
        blendPass.setUniform('texture1', this._prevTexture);
        blendPass.setUniform('texture2', ssrTexture);
        blendPass.material.set({
            'weight1': frame >= 1 ? 0.95 : 0,
            'weight2': frame >= 1 ? 0.05 : 1
            // weight1: frame >= 1 ? 1 : 0,
            // weight2: 1
        });
        blendPass.render(renderer);
    }

    frameBuffer.attach(texture2);
    blurPass1.setUniform('texture', this._physicallyCorrect ? this._currentTexture : ssrTexture);
    blurPass1.render(renderer);

    frameBuffer.attach(texture3);
    blurPass2.setUniform('texture', texture2);
    blurPass2.render(renderer);
    frameBuffer.unbind(renderer);

    if (this._physicallyCorrect) {
        var tmp = this._prevTexture;
        this._prevTexture = this._currentTexture;
        this._currentTexture = tmp;
    }
};

SSRPass.prototype.getTargetTexture = function () {
    return this._texture3;
};

SSRPass.prototype.setParameter = function (name, val) {
    if (name === 'maxIteration') {
        this._ssrPass.material.define('fragment', 'MAX_ITERATION', val);
    }
    else {
        this._ssrPass.setUniform(name, val);
    }
};

SSRPass.prototype.setPhysicallyCorrect = function (isPhysicallyCorrect) {
    if (isPhysicallyCorrect) {
        if (!this._normalDistribution) {
            this._normalDistribution = util_cubemap.generateNormalDistribution(64, this._totalSamples);
        }
        this._ssrPass.material.define('fragment', 'PHYSICALLY_CORRECT');
        this._ssrPass.material.set('normalDistribution', this._normalDistribution);
        this._ssrPass.material.set('normalDistributionSize', [64, this._totalSamples]);
    }
    else {
        this._ssrPass.material.undefine('fragment', 'PHYSICALLY_CORRECT');
    }

    this._physicallyCorrect = isPhysicallyCorrect;
};

SSRPass.prototype.setSSAOTexture = function (texture) {
    var blendPass = this._blurPass2;
    if (texture) {
        blendPass.material.enableTexture('ssaoTex');
        blendPass.material.set('ssaoTex', texture);
    }
    else {
        blendPass.material.disableTexture('ssaoTex');
    }
};

SSRPass.prototype.isFinished = function (frame) {
    if (this._physicallyCorrect) {
        return frame > (this._totalSamples / this._samplePerFrame);
    }
    else {
        return true;
    }
};

SSRPass.prototype.dispose = function (renderer) {
    this._ssrTexture.dispose(renderer);
    this._texture2.dispose(renderer);
    this._texture3.dispose(renderer);
    this._prevTexture.dispose(renderer);
    this._currentTexture.dispose(renderer);
    this._frameBuffer.dispose(renderer);
};

/* harmony default export */ const effect_SSRPass = (SSRPass);
;// CONCATENATED MODULE: ./src/effect/poissonKernel.js
// Based on https://bl.ocks.org/mbostock/19168c663618b707158

/* harmony default export */ const poissonKernel = ([
0.0, 0.0,
-0.321585265978, -0.154972575841,
0.458126042375, 0.188473391593,
0.842080129861, 0.527766490688,
0.147304551086, -0.659453822776,
-0.331943915203, -0.940619700594,
0.0479226680259, 0.54812163202,
0.701581552186, -0.709825561388,
-0.295436780218, 0.940589268233,
-0.901489676764, 0.237713156085,
0.973570876096, -0.109899459384,
-0.866792314779, -0.451805525005,
0.330975007087, 0.800048655954,
-0.344275183665, 0.381779221166,
-0.386139432542, -0.437418421534,
-0.576478634965, -0.0148463392551,
0.385798197415, -0.262426961053,
-0.666302061145, 0.682427250835,
-0.628010632582, -0.732836215494,
0.10163141741, -0.987658134403,
0.711995289051, -0.320024291314,
0.0296005138058, 0.950296523438,
0.0130612307608, -0.351024443122,
-0.879596633704, -0.10478487883,
0.435712737232, 0.504254490347,
0.779203817497, 0.206477676721,
0.388264289969, -0.896736162545,
-0.153106280781, -0.629203242522,
-0.245517550697, 0.657969239148,
0.126830499058, 0.26862328493,
-0.634888119007, -0.302301223431,
0.617074219636, 0.779817204925
]);
;// CONCATENATED MODULE: ./src/util/shader/normal.glsl.js
/* harmony default export */ const normal_glsl = ("@export ecgl.normal.vertex\n\n@import ecgl.common.transformUniforms\n\n@import ecgl.common.uv.header\n\n@import ecgl.common.attributes\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\n@import ecgl.common.normalMap.vertexHeader\n\n@import ecgl.common.vertexAnimation.header\n\nvoid main()\n{\n\n @import ecgl.common.vertexAnimation.main\n\n @import ecgl.common.uv.main\n\n v_Normal = normalize((worldInverseTranspose * vec4(normal, 0.0)).xyz);\n v_WorldPosition = (world * vec4(pos, 1.0)).xyz;\n\n @import ecgl.common.normalMap.vertexMain\n\n gl_Position = worldViewProjection * vec4(pos, 1.0);\n\n}\n\n\n@end\n\n\n@export ecgl.normal.fragment\n\n#define ROUGHNESS_CHANEL 0\n\nuniform bool useBumpMap;\nuniform bool useRoughnessMap;\nuniform bool doubleSide;\nuniform float roughness;\n\n@import ecgl.common.uv.fragmentHeader\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform mat4 viewInverse : VIEWINVERSE;\n\n@import ecgl.common.normalMap.fragmentHeader\n@import ecgl.common.bumpMap.header\n\nuniform sampler2D roughnessMap;\n\nvoid main()\n{\n vec3 N = v_Normal;\n \n bool flipNormal = false;\n if (doubleSide) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n\n if (dot(N, V) < 0.0) {\n flipNormal = true;\n }\n }\n\n @import ecgl.common.normalMap.fragmentMain\n\n if (useBumpMap) {\n N = bumpNormal(v_WorldPosition, v_Normal, N);\n }\n\n float g = 1.0 - roughness;\n\n if (useRoughnessMap) {\n float g2 = 1.0 - texture2D(roughnessMap, v_DetailTexcoord)[ROUGHNESS_CHANEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n\n if (flipNormal) {\n N = -N;\n }\n\n gl_FragColor.rgb = (N.xyz + 1.0) * 0.5;\n gl_FragColor.a = g;\n}\n@end");

;// CONCATENATED MODULE: ./src/effect/NormalPass.js
// NormalPass will generate normal and depth data.

// TODO Animation









src_Shader.import(normal_glsl);

function attachTextureToSlot(renderer, program, symbol, texture, slot) {
    var gl = renderer.gl;
    program.setUniform(gl, '1i', symbol, slot);

    gl.activeTexture(gl.TEXTURE0 + slot);
    // Maybe texture is not loaded yet;
    if (texture.isRenderable()) {
        texture.bind(renderer);
    }
    else {
        // Bind texture to null
        texture.unbind(renderer);
    }
}

// TODO Use globalShader insteadof globalMaterial?
function getBeforeRenderHook (renderer, defaultNormalMap, defaultBumpMap, defaultRoughnessMap, normalMaterial) {

    var previousNormalMap;
    var previousBumpMap;
    var previousRoughnessMap;
    var previousRenderable;
    var gl = renderer.gl;

    return function (renderable, normalMaterial, prevNormalMaterial) {
        // Material not change
        if (previousRenderable && previousRenderable.material === renderable.material) {
            return;
        }

        var material = renderable.material;
        var program = renderable.__program;

        var roughness = material.get('roughness');
        if (roughness == null) {
            roughness = 1;
        }

        var normalMap = material.get('normalMap') || defaultNormalMap;
        var roughnessMap = material.get('roughnessMap');
        var bumpMap = material.get('bumpMap');
        var uvRepeat = material.get('uvRepeat');
        var uvOffset = material.get('uvOffset');
        var detailUvRepeat = material.get('detailUvRepeat');
        var detailUvOffset = material.get('detailUvOffset');

        var useBumpMap = !!bumpMap && material.isTextureEnabled('bumpMap');
        var useRoughnessMap = !!roughnessMap && material.isTextureEnabled('roughnessMap');
        var doubleSide = material.isDefined('fragment', 'DOUBLE_SIDED');

        bumpMap = bumpMap || defaultBumpMap;
        roughnessMap = roughnessMap || defaultRoughnessMap;

        if (prevNormalMaterial !== normalMaterial) {
            normalMaterial.set('normalMap', normalMap);
            normalMaterial.set('bumpMap', bumpMap);
            normalMaterial.set('roughnessMap', roughnessMap);
            normalMaterial.set('useBumpMap', useBumpMap);
            normalMaterial.set('useRoughnessMap', useRoughnessMap);
            normalMaterial.set('doubleSide', doubleSide);
            uvRepeat != null && normalMaterial.set('uvRepeat', uvRepeat);
            uvOffset != null && normalMaterial.set('uvOffset', uvOffset);
            detailUvRepeat != null && normalMaterial.set('detailUvRepeat', detailUvRepeat);
            detailUvOffset != null && normalMaterial.set('detailUvOffset', detailUvOffset);

            normalMaterial.set('roughness', roughness);
        }
        else {
            program.setUniform(gl, '1f', 'roughness', roughness);

            if (previousNormalMap !== normalMap) {
                attachTextureToSlot(renderer, program, 'normalMap', normalMap, 0);
            }
            if (previousBumpMap !== bumpMap && bumpMap) {
                attachTextureToSlot(renderer, program, 'bumpMap', bumpMap, 1);
            }
            if (previousRoughnessMap !== roughnessMap && roughnessMap) {
                attachTextureToSlot(renderer, program, 'roughnessMap', roughnessMap, 2);
            }
            if (uvRepeat != null) {
                program.setUniform(gl, '2f', 'uvRepeat', uvRepeat);
            }
            if (uvOffset != null) {
                program.setUniform(gl, '2f', 'uvOffset', uvOffset);
            }
            if (detailUvRepeat != null) {
                program.setUniform(gl, '2f', 'detailUvRepeat', detailUvRepeat);
            }
            if (detailUvOffset != null) {
                program.setUniform(gl, '2f', 'detailUvOffset', detailUvOffset);
            }
            program.setUniform(gl, '1i', 'useBumpMap', +useBumpMap);
            program.setUniform(gl, '1i', 'useRoughnessMap', +useRoughnessMap);
            program.setUniform(gl, '1i', 'doubleSide', +doubleSide);
        }

        previousNormalMap = normalMap;
        previousBumpMap = bumpMap;
        previousRoughnessMap = roughnessMap;

        previousRenderable = renderable;
    };
}

function NormalPass(opt) {
    opt = opt || {};

    this._depthTex = new src_Texture2D({
        format: src_Texture.DEPTH_COMPONENT,
        type: src_Texture.UNSIGNED_INT
    });
    this._normalTex = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });

    this._framebuffer = new src_FrameBuffer();
    this._framebuffer.attach(this._normalTex);
    this._framebuffer.attach(this._depthTex, src_FrameBuffer.DEPTH_ATTACHMENT);

    this._normalMaterial = new src_Material({
        shader: new src_Shader(
            src_Shader.source('ecgl.normal.vertex'),
            src_Shader.source('ecgl.normal.fragment')
        )
    });
    this._normalMaterial.enableTexture(['normalMap', 'bumpMap', 'roughnessMap']);

    this._defaultNormalMap = util_texture.createBlank('#000');
    this._defaultBumpMap = util_texture.createBlank('#000');
    this._defaultRoughessMap = util_texture.createBlank('#000');


    this._debugPass = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.output')
    });
    this._debugPass.setUniform('texture', this._normalTex);
    this._debugPass.material.undefine('fragment', 'OUTPUT_ALPHA');
}

NormalPass.prototype.getDepthTexture = function () {
    return this._depthTex;
};

NormalPass.prototype.getNormalTexture = function () {
    return this._normalTex;
};

NormalPass.prototype.update = function (renderer, scene, camera) {

    var width = renderer.getWidth();
    var height = renderer.getHeight();

    var depthTexture = this._depthTex;
    var normalTexture = this._normalTex;
    var normalMaterial = this._normalMaterial;

    depthTexture.width = width;
    depthTexture.height = height;
    normalTexture.width = width;
    normalTexture.height = height;

    var opaqueList = scene.getRenderList(camera).opaque;

    this._framebuffer.bind(renderer);
    renderer.gl.clearColor(0, 0, 0, 0);
    renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT);
    renderer.gl.disable(renderer.gl.BLEND);

    renderer.renderPass(opaqueList, camera, {
        getMaterial: function () {
            return normalMaterial;
        },
        ifRender: function (object) {
            return object.renderNormal;
        },
        beforeRender: getBeforeRenderHook(
            renderer, this._defaultNormalMap, this._defaultBumpMap, this._defaultRoughessMap, this._normalMaterial
        ),
        sort: renderer.opaqueSortCompare
    });
    this._framebuffer.unbind(renderer);
};

NormalPass.prototype.renderDebug = function (renderer) {
    this._debugPass.render(renderer);
};

NormalPass.prototype.dispose = function (renderer) {
    this._depthTex.dispose(renderer);
    this._normalTex.dispose(renderer);
}

/* harmony default export */ const effect_NormalPass = (NormalPass);
;// CONCATENATED MODULE: ./src/effect/EdgePass.js








function EdgePass(opt) {
    opt = opt || {};

    this._edgePass = new compositor_Pass({
        fragment: src_Shader.source('ecgl.edge')
    });

    this._edgePass.setUniform('normalTexture', opt.normalTexture);
    this._edgePass.setUniform('depthTexture', opt.depthTexture);

    this._targetTexture = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });

    this._frameBuffer = new src_FrameBuffer();
    this._frameBuffer.attach(this._targetTexture);
}

EdgePass.prototype.update = function (renderer, camera, sourceTexture, frame) {
    var width = renderer.getWidth();
    var height = renderer.getHeight();
    var texture = this._targetTexture;
    texture.width = width;
    texture.height = height;
    var frameBuffer = this._frameBuffer;

    frameBuffer.bind(renderer);
    this._edgePass.setUniform('projectionInv', camera.invProjectionMatrix.array);
    this._edgePass.setUniform('textureSize', [width, height]);
    this._edgePass.setUniform('texture', sourceTexture);
    this._edgePass.render(renderer);

    frameBuffer.unbind(renderer);
};

EdgePass.prototype.getTargetTexture = function () {
    return this._targetTexture;
};

EdgePass.prototype.setParameter = function (name, val) {
    this._edgePass.setUniform(name, val);
};

EdgePass.prototype.dispose = function (renderer) {
    this._targetTexture.dispose(renderer);
    this._frameBuffer.dispose(renderer);
};

/* harmony default export */ const effect_EdgePass = (EdgePass);
;// CONCATENATED MODULE: ./src/effect/composite.js
/* harmony default export */ const composite = ({
    'type' : 'compositor',
    'nodes' : [
        {
            'name': 'source',
            'type': 'texture',
            'outputs': {
                'color': {}
            }
        },
        {
            'name': 'source_half',
            'shader': '#source(clay.compositor.downsample)',
            'inputs': {
                'texture': 'source'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'width': 'expr(width * 1.0 / 2)',
                        'height': 'expr(height * 1.0 / 2)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'textureSize': 'expr( [width * 1.0, height * 1.0] )'
            }
        },


        {
            'name' : 'bright',
            'shader' : '#source(clay.compositor.bright)',
            'inputs' : {
                'texture' : 'source_half'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 2)',
                        'height' : 'expr(height * 1.0 / 2)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'threshold' : 2,
                'scale': 4,
                'textureSize': 'expr([width * 1.0 / 2, height / 2])'
            }
        },

        {
            'name': 'bright_downsample_4',
            'shader' : '#source(clay.compositor.downsample)',
            'inputs' : {
                'texture' : 'bright'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 4)',
                        'height' : 'expr(height * 1.0 / 4)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'textureSize': 'expr( [width * 1.0 / 2, height / 2] )'
            }
        },
        {
            'name': 'bright_downsample_8',
            'shader' : '#source(clay.compositor.downsample)',
            'inputs' : {
                'texture' : 'bright_downsample_4'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 8)',
                        'height' : 'expr(height * 1.0 / 8)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'textureSize': 'expr( [width * 1.0 / 4, height / 4] )'
            }
        },
        {
            'name': 'bright_downsample_16',
            'shader' : '#source(clay.compositor.downsample)',
            'inputs' : {
                'texture' : 'bright_downsample_8'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 16)',
                        'height' : 'expr(height * 1.0 / 16)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'textureSize': 'expr( [width * 1.0 / 8, height / 8] )'
            }
        },
        {
            'name': 'bright_downsample_32',
            'shader' : '#source(clay.compositor.downsample)',
            'inputs' : {
                'texture' : 'bright_downsample_16'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 32)',
                        'height' : 'expr(height * 1.0 / 32)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'textureSize': 'expr( [width * 1.0 / 16, height / 16] )'
            }
        },


        {
            'name' : 'bright_upsample_16_blur_h',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_downsample_32'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 16)',
                        'height' : 'expr(height * 1.0 / 16)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 0.0,
                'textureSize': 'expr( [width * 1.0 / 32, height / 32] )'
            }
        },
        {
            'name' : 'bright_upsample_16_blur_v',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_upsample_16_blur_h'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 16)',
                        'height' : 'expr(height * 1.0 / 16)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 1.0,
                'textureSize': 'expr( [width * 1.0 / 16, height * 1.0 / 16] )'
            }
        },



        {
            'name' : 'bright_upsample_8_blur_h',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_downsample_16'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 8)',
                        'height' : 'expr(height * 1.0 / 8)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 0.0,
                'textureSize': 'expr( [width * 1.0 / 16, height * 1.0 / 16] )'
            }
        },
        {
            'name' : 'bright_upsample_8_blur_v',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_upsample_8_blur_h'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 8)',
                        'height' : 'expr(height * 1.0 / 8)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 1.0,
                'textureSize': 'expr( [width * 1.0 / 8, height * 1.0 / 8] )'
            }
        },
        {
            'name' : 'bright_upsample_8_blend',
            'shader' : '#source(clay.compositor.blend)',
            'inputs' : {
                'texture1' : 'bright_upsample_8_blur_v',
                'texture2' : 'bright_upsample_16_blur_v'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 8)',
                        'height' : 'expr(height * 1.0 / 8)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'weight1' : 0.3,
                'weight2' : 0.7
            }
        },


        {
            'name' : 'bright_upsample_4_blur_h',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_downsample_8'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 4)',
                        'height' : 'expr(height * 1.0 / 4)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 0.0,
                'textureSize': 'expr( [width * 1.0 / 8, height * 1.0 / 8] )'
            }
        },
        {
            'name' : 'bright_upsample_4_blur_v',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_upsample_4_blur_h'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 4)',
                        'height' : 'expr(height * 1.0 / 4)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 1.0,
                'textureSize': 'expr( [width * 1.0 / 4, height * 1.0 / 4] )'
            }
        },
        {
            'name' : 'bright_upsample_4_blend',
            'shader' : '#source(clay.compositor.blend)',
            'inputs' : {
                'texture1' : 'bright_upsample_4_blur_v',
                'texture2' : 'bright_upsample_8_blend'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 4)',
                        'height' : 'expr(height * 1.0 / 4)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'weight1' : 0.3,
                'weight2' : 0.7
            }
        },





        {
            'name' : 'bright_upsample_2_blur_h',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_downsample_4'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 2)',
                        'height' : 'expr(height * 1.0 / 2)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 0.0,
                'textureSize': 'expr( [width * 1.0 / 4, height * 1.0 / 4] )'
            }
        },
        {
            'name' : 'bright_upsample_2_blur_v',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_upsample_2_blur_h'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 2)',
                        'height' : 'expr(height * 1.0 / 2)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 1.0,
                'textureSize': 'expr( [width * 1.0 / 2, height * 1.0 / 2] )'
            }
        },
        {
            'name' : 'bright_upsample_2_blend',
            'shader' : '#source(clay.compositor.blend)',
            'inputs' : {
                'texture1' : 'bright_upsample_2_blur_v',
                'texture2' : 'bright_upsample_4_blend'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0 / 2)',
                        'height' : 'expr(height * 1.0 / 2)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'weight1' : 0.3,
                'weight2' : 0.7
            }
        },



        {
            'name' : 'bright_upsample_full_blur_h',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0)',
                        'height' : 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 0.0,
                'textureSize': 'expr( [width * 1.0 / 2, height * 1.0 / 2] )'
            }
        },
        {
            'name' : 'bright_upsample_full_blur_v',
            'shader' : '#source(clay.compositor.gaussian_blur)',
            'inputs' : {
                'texture' : 'bright_upsample_full_blur_h'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0)',
                        'height' : 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'blurSize' : 1,
                'blurDir': 1.0,
                'textureSize': 'expr( [width * 1.0, height * 1.0] )'
            }
        },
        {
            'name' : 'bloom_composite',
            'shader' : '#source(clay.compositor.blend)',
            'inputs' : {
                'texture1' : 'bright_upsample_full_blur_v',
                'texture2' : 'bright_upsample_2_blend'
            },
            'outputs' : {
                'color' : {
                    'parameters' : {
                        'width' : 'expr(width * 1.0)',
                        'height' : 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters' : {
                'weight1' : 0.3,
                'weight2' : 0.7
            }
        },


        {
            'name': 'coc',
            'shader': '#source(ecgl.dof.coc)',
            'outputs': {
                'color': {
                    'parameters': {
                        'minFilter': 'NEAREST',
                        'magFilter': 'NEAREST',
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)'
                    }
                }
            },
            'parameters': {
                'focalDist': 50,
                'focalRange': 30
            }
        },

        {
            'name': 'dof_far_blur',
            'shader': '#source(ecgl.dof.diskBlur)',
            'inputs': {
                'texture': 'source',
                'coc': 'coc'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters': {
                'textureSize': 'expr( [width * 1.0, height * 1.0] )'
            }
        },
        {
            'name': 'dof_near_blur',
            'shader': '#source(ecgl.dof.diskBlur)',
            'inputs': {
                'texture': 'source',
                'coc': 'coc'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            },
            'parameters': {
                'textureSize': 'expr( [width * 1.0, height * 1.0] )'
            },
            'defines': {
                'BLUR_NEARFIELD': null
            }
        },


        {
            'name': 'dof_coc_blur',
            'shader': '#source(ecgl.dof.diskBlur)',
            'inputs': {
                'texture': 'coc'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'minFilter': 'NEAREST',
                        'magFilter': 'NEAREST',
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)'
                    }
                }
            },
            'parameters': {
                'textureSize': 'expr( [width * 1.0, height * 1.0] )'
            },
            'defines': {
                'BLUR_COC': null
            }
        },

        {
            'name': 'dof_composite',
            'shader': '#source(ecgl.dof.composite)',
            'inputs': {
                'original': 'source',
                'blurred': 'dof_far_blur',
                'nearfield': 'dof_near_blur',
                'coc': 'coc',
                'nearcoc': 'dof_coc_blur'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)',
                        'type': 'HALF_FLOAT'
                    }
                }
            }
        },
        {
            'name' : 'composite',
            'shader' : '#source(clay.compositor.hdr.composite)',
            'inputs' : {
                'texture': 'source',
                'bloom' : 'bloom_composite'
            },
            'outputs': {
                'color': {
                    'parameters': {
                        'width': 'expr(width * 1.0)',
                        'height': 'expr(height * 1.0)'
                    }
                }
            },
            'defines': {
                // Images are all premultiplied alpha before composite because of blending.
                // 'PREMULTIPLY_ALPHA': null,
                // 'DEBUG': 2
            }
        },
        {
            'name' : 'FXAA',
            'shader' : '#source(clay.compositor.fxaa)',
            'inputs' : {
                'texture' : 'composite'
            }
        }
    ]
});
;// CONCATENATED MODULE: ./src/effect/DOF.glsl.js
/* harmony default export */ const DOF_glsl = ("@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import clay.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import clay.util.rgbm\n@import clay.util.float\n\nvoid main()\n{\n vec4 blurredColor = texture2D(blurred, v_Texcoord);\n vec4 originalColor = texture2D(original, v_Texcoord);\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = texture2D(nearfield, v_Texcoord);\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import clay.util.rgbm\n@import clay.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = texel;\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n texel.rgb *= texel.a;\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n color.rgb /= (color.a + 0.0001);\n gl_FragColor = color;\n#endif\n}\n\n@end");

;// CONCATENATED MODULE: ./src/effect/edge.glsl.js
/* harmony default export */ const edge_glsl = ("@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end");

;// CONCATENATED MODULE: ./src/effect/EffectCompositor.js


























src_Shader.import(blur_glsl);
src_Shader.import(lut_glsl);
src_Shader.import(output_glsl);
src_Shader.import(bright_glsl);
src_Shader.import(downsample_glsl);
src_Shader.import(upsample_glsl);
src_Shader.import(hdr_glsl);
src_Shader.import(blend_glsl);
src_Shader.import(fxaa_glsl);
src_Shader.import(DOF_glsl);
src_Shader.import(edge_glsl);


function makeCommonOutputs(getWidth, getHeight) {
    return {
        color: {
            parameters: {
                width: getWidth,
                height: getHeight
            }
        }
    };
}

var FINAL_NODES_CHAIN = ['composite', 'FXAA'];

function EffectCompositor() {
    this._width;
    this._height;
    this._dpr;


    this._sourceTexture = new src_Texture2D({
        type: src_Texture.HALF_FLOAT
    });
    this._depthTexture = new src_Texture2D({
        format: src_Texture.DEPTH_COMPONENT,
        type: src_Texture.UNSIGNED_INT
    });

    this._framebuffer = new src_FrameBuffer();
    this._framebuffer.attach(this._sourceTexture);
    this._framebuffer.attach(this._depthTexture, src_FrameBuffer.DEPTH_ATTACHMENT);

    this._normalPass = new effect_NormalPass();

    this._compositor = compositor_createCompositor(composite);

    var sourceNode = this._compositor.getNodeByName('source');
    sourceNode.texture = this._sourceTexture;
    var cocNode = this._compositor.getNodeByName('coc');

    this._sourceNode = sourceNode;
    this._cocNode = cocNode;
    this._compositeNode = this._compositor.getNodeByName('composite');
    this._fxaaNode = this._compositor.getNodeByName('FXAA');

    this._dofBlurNodes = ['dof_far_blur', 'dof_near_blur', 'dof_coc_blur'].map(function (name) {
        return this._compositor.getNodeByName(name);
    }, this);

    this._dofBlurKernel = 0;
    this._dofBlurKernelSize = new Float32Array(0);

    this._finalNodesChain = FINAL_NODES_CHAIN.map(function (name) {
        return this._compositor.getNodeByName(name);
    }, this);

    var gBufferObj = {
        normalTexture: this._normalPass.getNormalTexture(),
        depthTexture: this._normalPass.getDepthTexture()
    };
    this._ssaoPass = new effect_SSAOPass(gBufferObj);
    this._ssrPass = new effect_SSRPass(gBufferObj);
    this._edgePass = new effect_EdgePass(gBufferObj);
}

EffectCompositor.prototype.resize = function (width, height, dpr) {
    dpr = dpr || 1;
    var width = width * dpr;
    var height = height * dpr;
    var sourceTexture = this._sourceTexture;
    var depthTexture = this._depthTexture;

    sourceTexture.width = width;
    sourceTexture.height = height;
    depthTexture.width = width;
    depthTexture.height = height;

    var rendererMock = {
        getWidth: function () {
            return width;
        },
        getHeight: function () {
            return height;
        },
        getDevicePixelRatio: function () {
            return dpr;
        }
    };
    function wrapCallback(obj, key) {
        if (typeof obj[key] === 'function') {
            var oldFunc = obj[key].__original || obj[key];
            // Use viewport width/height instead of renderer width/height
            obj[key] = function (renderer) {
                return oldFunc.call(this, rendererMock);
            };
            obj[key].__original = oldFunc;
        }
    }
    this._compositor.nodes.forEach(function (node) {
        for (var outKey in node.outputs) {
            var parameters = node.outputs[outKey].parameters;
            if (parameters) {
                wrapCallback(parameters, 'width');
                wrapCallback(parameters, 'height');
            }
        }
        for (var paramKey in node.parameters) {
            wrapCallback(node.parameters, paramKey);
        }
    });

    this._width = width;
    this._height = height;
    this._dpr = dpr;
};

EffectCompositor.prototype.getWidth = function () {
    return this._width;
};
EffectCompositor.prototype.getHeight = function () {
    return this._height;
};

EffectCompositor.prototype._ifRenderNormalPass = function () {
    return this._enableSSAO || this._enableEdge || this._enableSSR;
};

EffectCompositor.prototype._getPrevNode = function (node) {
    var idx = FINAL_NODES_CHAIN.indexOf(node.name) - 1;
    var prevNode = this._finalNodesChain[idx];
    while (prevNode && !this._compositor.getNodeByName(prevNode.name)) {
        idx -= 1;
        prevNode = this._finalNodesChain[idx];
    }
    return prevNode;
};
EffectCompositor.prototype._getNextNode = function (node) {
    var idx = FINAL_NODES_CHAIN.indexOf(node.name) + 1;
    var nextNode = this._finalNodesChain[idx];
    while (nextNode && !this._compositor.getNodeByName(nextNode.name)) {
        idx += 1;
        nextNode = this._finalNodesChain[idx];
    }
    return nextNode;
};
EffectCompositor.prototype._addChainNode = function (node) {
    var prevNode = this._getPrevNode(node);
    var nextNode = this._getNextNode(node);
    if (!prevNode) {
        return;
    }

    node.inputs.texture = prevNode.name;
    if (nextNode) {
        node.outputs = makeCommonOutputs(this.getWidth.bind(this), this.getHeight.bind(this));
        nextNode.inputs.texture = node.name;
    }
    else {
        node.outputs = null;
    }
    this._compositor.addNode(node);
};
EffectCompositor.prototype._removeChainNode = function (node) {
    var prevNode = this._getPrevNode(node);
    var nextNode = this._getNextNode(node);
    if (!prevNode) {
        return;
    }

    if (nextNode) {
        prevNode.outputs = makeCommonOutputs(this.getWidth.bind(this), this.getHeight.bind(this));
        nextNode.inputs.texture = prevNode.name;
    }
    else {
        prevNode.outputs = null;
    }
    this._compositor.removeNode(node);
};
/**
 * Update normal
 */
EffectCompositor.prototype.updateNormal = function (renderer, scene, camera, frame) {
    if (this._ifRenderNormalPass()) {
        this._normalPass.update(renderer, scene, camera);
    }
};

/**
 * Render SSAO after render the scene, before compositing
 */
EffectCompositor.prototype.updateSSAO = function (renderer, scene, camera, frame) {
    this._ssaoPass.update(renderer, camera, frame);
};

/**
 * Enable SSAO effect
 */
EffectCompositor.prototype.enableSSAO = function () {
    this._enableSSAO = true;
};

/**
 * Disable SSAO effect
 */
EffectCompositor.prototype.disableSSAO = function () {
    this._enableSSAO = false;
};

/**
 * Enable SSR effect
 */
EffectCompositor.prototype.enableSSR = function () {
    this._enableSSR = true;
    // this._normalPass.enableTargetTexture3 = true;
};
/**
 * Disable SSR effect
 */
EffectCompositor.prototype.disableSSR = function () {
    this._enableSSR = false;
    // this._normalPass.enableTargetTexture3 = false;
};

/**
 * Render SSAO after render the scene, before compositing
 */
EffectCompositor.prototype.getSSAOTexture = function () {
    return this._ssaoPass.getTargetTexture();
};

/**
 * @return {clay.FrameBuffer}
 */
EffectCompositor.prototype.getSourceFrameBuffer = function () {
    return this._framebuffer;
};

/**
 * @return {clay.Texture2D}
 */
EffectCompositor.prototype.getSourceTexture = function () {
    return this._sourceTexture;
};

/**
 * Disable fxaa effect
 */
EffectCompositor.prototype.disableFXAA = function () {
    this._removeChainNode(this._fxaaNode);
};

/**
 * Enable fxaa effect
 */
EffectCompositor.prototype.enableFXAA = function () {
    this._addChainNode(this._fxaaNode);
};

/**
 * Enable bloom effect
 */
EffectCompositor.prototype.enableBloom = function () {
    this._compositeNode.inputs.bloom = 'bloom_composite';
    this._compositor.dirty();
};

/**
 * Disable bloom effect
 */
EffectCompositor.prototype.disableBloom = function () {
    this._compositeNode.inputs.bloom = null;
    this._compositor.dirty();
};

/**
 * Enable depth of field effect
 */
EffectCompositor.prototype.enableDOF = function () {
    this._compositeNode.inputs.texture = 'dof_composite';
    this._compositor.dirty();
};
/**
 * Disable depth of field effect
 */
EffectCompositor.prototype.disableDOF = function () {
    this._compositeNode.inputs.texture = 'source';
    this._compositor.dirty();
};

/**
 * Enable color correction
 */
EffectCompositor.prototype.enableColorCorrection = function () {
    this._compositeNode.define('COLOR_CORRECTION');
    this._enableColorCorrection = true;
};
/**
 * Disable color correction
 */
EffectCompositor.prototype.disableColorCorrection = function () {
    this._compositeNode.undefine('COLOR_CORRECTION');
    this._enableColorCorrection = false;
};

/**
 * Enable edge detection
 */
EffectCompositor.prototype.enableEdge = function () {
    this._enableEdge = true;
};

/**
 * Disable edge detection
 */
EffectCompositor.prototype.disableEdge = function () {
    this._enableEdge = false;
};

/**
 * Set bloom intensity
 * @param {number} value
 */
EffectCompositor.prototype.setBloomIntensity = function (value) {
    this._compositeNode.setParameter('bloomIntensity', value);
};

EffectCompositor.prototype.setSSAOParameter = function (name, value) {
    switch (name) {
        case 'quality':
            // PENDING
            var kernelSize = ({
                low: 6,
                medium: 12,
                high: 32,
                ultra: 62
            })[value] || 12;
            this._ssaoPass.setParameter('kernelSize', kernelSize);
            break;
        case 'radius':
            this._ssaoPass.setParameter(name, value);
            this._ssaoPass.setParameter('bias', value / 200);
            break;
        case 'intensity':
            this._ssaoPass.setParameter(name, value);
            break;
        default:
            if (true) {
                console.warn('Unkown SSAO parameter ' + name);
            }
    }
};

EffectCompositor.prototype.setDOFParameter = function (name, value) {
    switch (name) {
        case 'focalDistance':
        case 'focalRange':
        case 'fstop':
            this._cocNode.setParameter(name, value);
            break;
        case 'blurRadius':
            for (var i = 0; i < this._dofBlurNodes.length; i++) {
                this._dofBlurNodes[i].setParameter('blurRadius', value);
            }
            break;
        case 'quality':
            var kernelSize = ({
                low: 4, medium: 8, high: 16, ultra: 32
            })[value] || 8;
            this._dofBlurKernelSize = kernelSize;
            for (var i = 0; i < this._dofBlurNodes.length; i++) {
                this._dofBlurNodes[i].pass.material.define('POISSON_KERNEL_SIZE', kernelSize);
            }
            this._dofBlurKernel = new Float32Array(kernelSize * 2);
            break;
        default:
            if (true) {
                console.warn('Unkown DOF parameter ' + name);
            }
    }
};

EffectCompositor.prototype.setSSRParameter = function (name, value) {
    if (value == null) {
        return;
    }
    switch (name) {
        case 'quality':
            // PENDING
            var maxIteration = ({
                low: 10,
                medium: 15,
                high: 30,
                ultra: 80
            })[value] || 20;
            var pixelStride = ({
                low: 32,
                medium: 16,
                high: 8,
                ultra: 4
            })[value] || 16;
            this._ssrPass.setParameter('maxIteration', maxIteration);
            this._ssrPass.setParameter('pixelStride', pixelStride);
            break;
        case 'maxRoughness':
            this._ssrPass.setParameter('minGlossiness', Math.max(Math.min(1.0 - value, 1.0), 0.0));
            break;
        case 'physical':
            this.setPhysicallyCorrectSSR(value);
            break;
        default:
            console.warn('Unkown SSR parameter ' + name);
    }
};

EffectCompositor.prototype.setPhysicallyCorrectSSR = function (physical) {
    this._ssrPass.setPhysicallyCorrect(physical);
};

/**
 * Set color of edge
 */
EffectCompositor.prototype.setEdgeColor = function (value) {
    var color = util_graphicGL.parseColor(value);
    this._edgePass.setParameter('edgeColor', color);
};

EffectCompositor.prototype.setExposure = function (value) {
    this._compositeNode.setParameter('exposure', Math.pow(2, value));
};

EffectCompositor.prototype.setColorLookupTexture = function (image, api) {
    this._compositeNode.pass.material.setTextureImage('lut', this._enableColorCorrection ? image : 'none', api, {
        minFilter: util_graphicGL.Texture.NEAREST,
        magFilter: util_graphicGL.Texture.NEAREST,
        flipY: false
    });
};
EffectCompositor.prototype.setColorCorrection = function (type, value) {
    this._compositeNode.setParameter(type, value);
};

EffectCompositor.prototype.isSSREnabled = function () {
    return this._enableSSR;
};

EffectCompositor.prototype.composite = function (renderer, scene, camera, framebuffer, frame) {

    var sourceTexture = this._sourceTexture;
    var targetTexture = sourceTexture;
    if (this._enableEdge) {
        this._edgePass.update(renderer, camera, sourceTexture, frame);
        sourceTexture = targetTexture = this._edgePass.getTargetTexture();
    }
    if (this._enableSSR) {
        this._ssrPass.update(renderer, camera, sourceTexture, frame);
        targetTexture = this._ssrPass.getTargetTexture();

        this._ssrPass.setSSAOTexture(
            this._enableSSAO ? this._ssaoPass.getTargetTexture() : null
        );
        // var lights = scene.getLights();
        // for (var i = 0; i < lights.length; i++) {
        //     if (lights[i].cubemap) {
        //         this._ssrPass.setAmbientCubemap(lights[i].cubemap, lights[i].intensity);
        //     }
        // }
    }
    this._sourceNode.texture = targetTexture;

    this._cocNode.setParameter('depth', this._depthTexture);

    var blurKernel = this._dofBlurKernel;
    var blurKernelSize = this._dofBlurKernelSize;
    var frameAll = Math.floor(poissonKernel.length / 2 / blurKernelSize);
    var kernelOffset = frame % frameAll;

    for (var i = 0; i < blurKernelSize * 2; i++) {
        blurKernel[i] = poissonKernel[i + kernelOffset * blurKernelSize * 2];
    }

    for (var i = 0; i < this._dofBlurNodes.length; i++) {
        this._dofBlurNodes[i].setParameter('percent', frame / 30.0);
        this._dofBlurNodes[i].setParameter('poissonKernel', blurKernel);
    }

    this._cocNode.setParameter('zNear', camera.near);
    this._cocNode.setParameter('zFar', camera.far);

    this._compositor.render(renderer, framebuffer);
};

EffectCompositor.prototype.dispose = function (renderer) {
    this._sourceTexture.dispose(renderer);
    this._depthTexture.dispose(renderer);
    this._framebuffer.dispose(renderer);
    this._compositor.dispose(renderer);

    this._normalPass.dispose(renderer);
    this._ssaoPass.dispose(renderer);
};

/* harmony default export */ const effect_EffectCompositor = (EffectCompositor);
;// CONCATENATED MODULE: ./src/effect/TemporalSuperSampling.js
// Temporal Super Sample for static Scene







function TemporalSuperSampling (frames) {
    var haltonSequence = [];

    for (var i = 0; i < 30; i++) {
        haltonSequence.push([effect_halton(i, 2), effect_halton(i, 3)]);
    }

    this._haltonSequence = haltonSequence;

    this._frame = 0;

    this._sourceTex = new src_Texture2D();
    this._sourceFb = new src_FrameBuffer();
    this._sourceFb.attach(this._sourceTex);

    // Frame texture before temporal supersampling
    this._prevFrameTex = new src_Texture2D();
    this._outputTex = new src_Texture2D();

    var blendPass = this._blendPass = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.blend')
    });
    blendPass.material.disableTexturesAll();
    blendPass.material.enableTexture(['texture1', 'texture2']);

    this._blendFb = new src_FrameBuffer({
        depthBuffer: false
    });

    this._outputPass = new compositor_Pass({
        fragment: src_Shader.source('clay.compositor.output'),
        // TODO, alpha is premultiplied?
        blendWithPrevious: true
    });
    this._outputPass.material.define('fragment', 'OUTPUT_ALPHA');
    this._outputPass.material.blend = function (_gl) {
        // FIXME.
        // Output is premultiplied alpha when BLEND is enabled ?
        // http://stackoverflow.com/questions/2171085/opengl-blending-with-previous-contents-of-framebuffer
        _gl.blendEquationSeparate(_gl.FUNC_ADD, _gl.FUNC_ADD);
        _gl.blendFuncSeparate(_gl.ONE, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA);
    };
}

TemporalSuperSampling.prototype = {

    constructor: TemporalSuperSampling,

    /**
     * Jitter camera projectionMatrix
     * @parma {clay.Renderer} renderer
     * @param {clay.Camera} camera
     */
    jitterProjection: function (renderer, camera) {
        var viewport = renderer.viewport;
        var dpr = viewport.devicePixelRatio || renderer.getDevicePixelRatio();
        var width = viewport.width * dpr;
        var height = viewport.height * dpr;

        var offset = this._haltonSequence[this._frame % this._haltonSequence.length];

        var translationMat = new math_Matrix4();
        translationMat.array[12] = (offset[0] * 2.0 - 1.0) / width;
        translationMat.array[13] = (offset[1] * 2.0 - 1.0) / height;

        math_Matrix4.mul(camera.projectionMatrix, translationMat, camera.projectionMatrix);

        math_Matrix4.invert(camera.invProjectionMatrix, camera.projectionMatrix);
    },

    /**
     * Reset accumulating frame
     */
    resetFrame: function () {
        this._frame = 0;
    },

    /**
     * Return current frame
     */
    getFrame: function () {
        return this._frame;
    },

    /**
     * Get source framebuffer for usage
     */
    getSourceFrameBuffer: function () {
        return this._sourceFb;
    },

    getOutputTexture: function () {
        return this._outputTex;
    },

    resize: function (width, height) {
        this._prevFrameTex.width = width;
        this._prevFrameTex.height = height;

        this._outputTex.width = width;
        this._outputTex.height = height;

        this._sourceTex.width = width;
        this._sourceTex.height = height;

        this._prevFrameTex.dirty();
        this._outputTex.dirty();
        this._sourceTex.dirty();
    },

    isFinished: function () {
        return this._frame >= this._haltonSequence.length;
    },

    render: function (renderer, sourceTex, notOutput) {
        var blendPass = this._blendPass;
        if (this._frame === 0) {
            // Direct output
            blendPass.setUniform('weight1', 0);
            blendPass.setUniform('weight2', 1);
        }
        else {
            blendPass.setUniform('weight1', 0.9);
            blendPass.setUniform('weight2', 0.1);
        }
        blendPass.setUniform('texture1', this._prevFrameTex);
        blendPass.setUniform('texture2', sourceTex || this._sourceTex);

        this._blendFb.attach(this._outputTex);
        this._blendFb.bind(renderer);
        blendPass.render(renderer);
        this._blendFb.unbind(renderer);

        if (!notOutput) {
            this._outputPass.setUniform('texture', this._outputTex);
            this._outputPass.render(renderer);
        }

        // Swap texture
        var tmp = this._prevFrameTex;
        this._prevFrameTex = this._outputTex;
        this._outputTex = tmp;

        this._frame++;
    },

    dispose: function (renderer) {
        this._sourceFb.dispose(renderer);
        this._blendFb.dispose(renderer);
        this._prevFrameTex.dispose(renderer);
        this._outputTex.dispose(renderer);
        this._sourceTex.dispose(renderer);
        this._outputPass.dispose(renderer);
        this._blendPass.dispose(renderer);
    }
};

/* harmony default export */ const effect_TemporalSuperSampling = (TemporalSuperSampling);
;// CONCATENATED MODULE: ./src/core/ViewGL.js
/*
 * @module echarts-gl/core/ViewGL
 * @author Yi Shen(http://github.com/pissang)
 */

















/**
 * @constructor
 * @alias module:echarts-gl/core/ViewGL
 * @param {string} [projection='perspective']
 */
function ViewGL(projection) {

    projection = projection || 'perspective';

    /**
     * @type {module:echarts-gl/core/LayerGL}
     */
    this.layer = null;
    /**
     * @type {clay.Scene}
     */
    this.scene = new src_Scene();

    /**
     * @type {clay.Node}
     */
    this.rootNode = this.scene;

    this.viewport = {
        x: 0, y: 0, width: 0, height: 0
    };

    this.setProjection(projection);

    this._compositor = new effect_EffectCompositor();

    this._temporalSS = new effect_TemporalSuperSampling();

    this._shadowMapPass = new ShadowMap();

    var pcfKernels = [];
    var off = 0;
    for (var i = 0; i < 30; i++) {
        var pcfKernel = [];
        for (var k = 0; k < 6; k++) {
            pcfKernel.push(effect_halton(off, 2) * 4.0 - 2.0);
            pcfKernel.push(effect_halton(off, 3) * 4.0 - 2.0);
            off++;
        }
        pcfKernels.push(pcfKernel);
    }
    this._pcfKernels = pcfKernels;

    this.scene.on('beforerender', function (renderer, scene, camera) {
        if (this.needsTemporalSS()) {
            this._temporalSS.jitterProjection(renderer, camera);
        }
    }, this);
}

/**
 * Set camera type of group
 * @param {string} cameraType 'perspective' | 'orthographic'
 */
ViewGL.prototype.setProjection = function (projection) {
    var oldCamera = this.camera;
    oldCamera && oldCamera.update();
    if (projection === 'perspective') {
        if (!(this.camera instanceof camera_Perspective)) {
            this.camera = new camera_Perspective();
            if (oldCamera) {
                this.camera.setLocalTransform(oldCamera.localTransform);
            }
        }
    }
    else {
        if (!(this.camera instanceof camera_Orthographic)) {
            this.camera = new camera_Orthographic();
            if (oldCamera) {
                this.camera.setLocalTransform(oldCamera.localTransform);
            }
        }
    }
    // PENDING
    this.camera.near = 0.1;
    this.camera.far = 2000;
};

/**
 * Set viewport of group
 * @param {number} x Viewport left bottom x
 * @param {number} y Viewport left bottom y
 * @param {number} width Viewport height
 * @param {number} height Viewport height
 * @param {number} [dpr=1]
 */
ViewGL.prototype.setViewport = function (x, y, width, height, dpr) {
    if (this.camera instanceof camera_Perspective) {
        this.camera.aspect = width / height;
    }
    dpr = dpr || 1;

    this.viewport.x = x;
    this.viewport.y = y;
    this.viewport.width = width;
    this.viewport.height = height;
    this.viewport.devicePixelRatio = dpr;

    // Source and output of compositor use high dpr texture.
    // But the intermediate texture of bloom, dof effects use fixed 1.0 dpr
    this._compositor.resize(width * dpr, height * dpr);
    this._temporalSS.resize(width * dpr, height * dpr);
};

/**
 * If contain screen point x, y
 * @param {number} x offsetX
 * @param {number} y offsetY
 * @return {boolean}
 */
ViewGL.prototype.containPoint = function (x, y) {
    var viewport = this.viewport;
    var height = this.layer.renderer.getHeight();
    // Flip y;
    y = height - y;
    return x >= viewport.x && y >= viewport.y
        && x <= viewport.x + viewport.width && y <= viewport.y + viewport.height;
};

/**
 * Cast a ray
 * @param {number} x offsetX
 * @param {number} y offsetY
 * @param {clay.math.Ray} out
 * @return {clay.math.Ray}
 */
var ndc = new math_Vector2();
ViewGL.prototype.castRay = function (x, y, out) {
    var renderer = this.layer.renderer;

    var oldViewport = renderer.viewport;
    renderer.viewport = this.viewport;
    renderer.screenToNDC(x, y, ndc);
    this.camera.castRay(ndc, out);
    renderer.viewport = oldViewport;

    return out;
};

/**
 * Prepare and update scene before render
 */
ViewGL.prototype.prepareRender = function () {
    this.scene.update();
    this.camera.update();
    this.scene.updateLights();
    var renderList = this.scene.updateRenderList(this.camera);

    this._needsSortProgressively = false;
    // If has any transparent mesh needs sort triangles progressively.
    for (var i = 0; i < renderList.transparent.length; i++) {
        var renderable = renderList.transparent[i];
        var geometry = renderable.geometry;
        if (geometry.needsSortVerticesProgressively && geometry.needsSortVerticesProgressively()) {
            this._needsSortProgressively = true;
        }
        if (geometry.needsSortTrianglesProgressively && geometry.needsSortTrianglesProgressively()) {
            this._needsSortProgressively = true;
        }
    }

    this._frame = 0;
    this._temporalSS.resetFrame();

    // var lights = this.scene.getLights();
    // for (var i = 0; i < lights.length; i++) {
    //     if (lights[i].cubemap) {
    //         if (this._compositor && this._compositor.isSSREnabled()) {
    //             lights[i].invisible = true;
    //         }
    //         else {
    //             lights[i].invisible = false;
    //         }
    //     }
    // }
};

ViewGL.prototype.render = function (renderer, accumulating) {
    this._doRender(renderer, accumulating, this._frame);
    this._frame++;
};

ViewGL.prototype.needsAccumulate = function () {
    return this.needsTemporalSS() || this._needsSortProgressively;
};

ViewGL.prototype.needsTemporalSS = function () {
    var enableTemporalSS = this._enableTemporalSS;
    if (enableTemporalSS === 'auto') {
        enableTemporalSS = this._enablePostEffect;
    }
    return enableTemporalSS;
};

ViewGL.prototype.hasDOF = function () {
    return this._enableDOF;
};

ViewGL.prototype.isAccumulateFinished = function () {
    return this.needsTemporalSS() ? this._temporalSS.isFinished()
        : (this._frame > 30);
};

ViewGL.prototype._doRender = function (renderer, accumulating, accumFrame) {

    var scene = this.scene;
    var camera = this.camera;

    accumFrame = accumFrame || 0;

    this._updateTransparent(renderer, scene, camera, accumFrame);

    if (!accumulating) {
        this._shadowMapPass.kernelPCF = this._pcfKernels[0];
        // Not render shadowmap pass in accumulating frame.
        this._shadowMapPass.render(renderer, scene, camera, true);
    }

    this._updateShadowPCFKernel(accumFrame);

    // Shadowmap will set clear color.
    var bgColor = renderer.clearColor;
    renderer.gl.clearColor(bgColor[0], bgColor[1], bgColor[2], bgColor[3]);

    if (this._enablePostEffect) {
        // normal render also needs to be jittered when have edge pass.
        if (this.needsTemporalSS()) {
            this._temporalSS.jitterProjection(renderer, camera);
        }
        this._compositor.updateNormal(renderer, scene, camera, this._temporalSS.getFrame());
    }

    // Always update SSAO to make sure have correct ssaoMap status
    this._updateSSAO(renderer, scene, camera, this._temporalSS.getFrame());

    if (this._enablePostEffect) {

        var frameBuffer = this._compositor.getSourceFrameBuffer();
        frameBuffer.bind(renderer);
        renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT);
        renderer.render(scene, camera, true, true);
        frameBuffer.unbind(renderer);

        if (this.needsTemporalSS() && accumulating) {
            this._compositor.composite(renderer, scene, camera, this._temporalSS.getSourceFrameBuffer(), this._temporalSS.getFrame());
            renderer.setViewport(this.viewport);
            this._temporalSS.render(renderer);
        }
        else {
            renderer.setViewport(this.viewport);
            this._compositor.composite(renderer, scene, camera, null, 0);
        }
    }
    else {
        if (this.needsTemporalSS() && accumulating) {
            var frameBuffer = this._temporalSS.getSourceFrameBuffer();
            frameBuffer.bind(renderer);
            renderer.saveClear();
            renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT;
            renderer.render(scene, camera, true, true);
            renderer.restoreClear();
            frameBuffer.unbind(renderer);

            renderer.setViewport(this.viewport);
            this._temporalSS.render(renderer);
        }
        else {
            renderer.setViewport(this.viewport);
            renderer.render(scene, camera, true, true);
        }
    }

    // this._shadowMapPass.renderDebug(renderer);
    // this._compositor._normalPass.renderDebug(renderer);
};

ViewGL.prototype._updateTransparent = function (renderer, scene, camera, frame) {

    var v3 = new math_Vector3();
    var invWorldTransform = new math_Matrix4();
    var cameraWorldPosition = camera.getWorldPosition();
    var transparentList = scene.getRenderList(camera).transparent;

    // Sort transparent object.
    for (var i = 0; i < transparentList.length; i++) {
        var renderable = transparentList[i];
        var geometry = renderable.geometry;
        math_Matrix4.invert(invWorldTransform, renderable.worldTransform);
        math_Vector3.transformMat4(v3, cameraWorldPosition, invWorldTransform);
        if (geometry.needsSortTriangles && geometry.needsSortTriangles()) {
            geometry.doSortTriangles(v3, frame);
        }
        if (geometry.needsSortVertices && geometry.needsSortVertices()) {
            geometry.doSortVertices(v3, frame);
        }
    }
};

ViewGL.prototype._updateSSAO = function (renderer, scene, camera) {
    var ifEnableSSAO = this._enableSSAO && this._enablePostEffect;
    if (ifEnableSSAO) {
        this._compositor.updateSSAO(renderer, scene, camera, this._temporalSS.getFrame());
    }
    var renderList = scene.getRenderList(camera);

    for (var i = 0; i < renderList.opaque.length; i++) {
        var renderable = renderList.opaque[i];
        // PENDING
        if (renderable.renderNormal) {
            renderable.material[ifEnableSSAO ? 'enableTexture' : 'disableTexture']('ssaoMap');
        }
        if (ifEnableSSAO) {
            renderable.material.set('ssaoMap', this._compositor.getSSAOTexture());
        }
    }
};

ViewGL.prototype._updateShadowPCFKernel = function (frame) {
    var pcfKernel = this._pcfKernels[frame % this._pcfKernels.length];
    var renderList = this.scene.getRenderList(this.camera);
    var opaqueList = renderList.opaque;
    for (var i = 0; i < opaqueList.length; i++) {
        if (opaqueList[i].receiveShadow) {
            opaqueList[i].material.set('pcfKernel', pcfKernel);
            opaqueList[i].material.define('fragment', 'PCF_KERNEL_SIZE', pcfKernel.length / 2);
        }
    }
};

ViewGL.prototype.dispose = function (renderer) {
    this._compositor.dispose(renderer.gl);
    this._temporalSS.dispose(renderer.gl);
    this._shadowMapPass.dispose(renderer);
};
/**
 * @param {module:echarts/Model} Post effect model
 */
ViewGL.prototype.setPostEffect = function (postEffectModel, api) {
    var compositor = this._compositor;
    this._enablePostEffect = postEffectModel.get('enable');
    var bloomModel = postEffectModel.getModel('bloom');
    var edgeModel = postEffectModel.getModel('edge');
    var dofModel = postEffectModel.getModel('DOF', postEffectModel.getModel('depthOfField'));
    var ssaoModel = postEffectModel.getModel('SSAO', postEffectModel.getModel('screenSpaceAmbientOcclusion'));
    var ssrModel = postEffectModel.getModel('SSR', postEffectModel.getModel('screenSpaceReflection'));
    var fxaaModel = postEffectModel.getModel('FXAA');
    var colorCorrModel = postEffectModel.getModel('colorCorrection');
    bloomModel.get('enable') ? compositor.enableBloom() : compositor.disableBloom();
    dofModel.get('enable') ? compositor.enableDOF() : compositor.disableDOF();
    ssrModel.get('enable') ? compositor.enableSSR() : compositor.disableSSR();
    colorCorrModel.get('enable') ? compositor.enableColorCorrection() : compositor.disableColorCorrection();
    edgeModel.get('enable') ? compositor.enableEdge() : compositor.disableEdge();
    fxaaModel.get('enable') ? compositor.enableFXAA() : compositor.disableFXAA();

    this._enableDOF = dofModel.get('enable');
    this._enableSSAO = ssaoModel.get('enable');

    this._enableSSAO ? compositor.enableSSAO() : compositor.disableSSAO();

    compositor.setBloomIntensity(bloomModel.get('intensity'));
    compositor.setEdgeColor(edgeModel.get('color'));
    compositor.setColorLookupTexture(colorCorrModel.get('lookupTexture'), api);
    compositor.setExposure(colorCorrModel.get('exposure'));

    ['radius', 'quality', 'intensity'].forEach(function (name) {
        compositor.setSSAOParameter(name, ssaoModel.get(name));
    });
    ['quality', 'maxRoughness', 'physical'].forEach(function (name) {
        compositor.setSSRParameter(name, ssrModel.get(name));
    });
    ['quality', 'focalDistance', 'focalRange', 'blurRadius', 'fstop'].forEach(function (name) {
        compositor.setDOFParameter(name, dofModel.get(name));
    });
    ['brightness', 'contrast', 'saturation'].forEach(function (name) {
        compositor.setColorCorrection(name, colorCorrModel.get(name));
    });

};

ViewGL.prototype.setDOFFocusOnPoint = function (depth) {
    if (this._enablePostEffect) {

        if (depth > this.camera.far || depth < this.camera.near) {
            return;
        }

        this._compositor.setDOFParameter('focalDistance', depth);
        return true;
    }
};

ViewGL.prototype.setTemporalSuperSampling = function (temporalSuperSamplingModel) {
    this._enableTemporalSS = temporalSuperSamplingModel.get('enable');
};

ViewGL.prototype.isLinearSpace = function () {
    return this._enablePostEffect;
};

ViewGL.prototype.setRootNode = function (rootNode) {
    if (this.rootNode === rootNode) {
        return;
    }
    var children = this.rootNode.children();
    for (var i = 0; i < children.length; i++) {
        rootNode.add(children[i]);
    }
    if (rootNode !== this.scene) {
        this.scene.add(rootNode);
    }

    this.rootNode = rootNode;
};
// Proxies
ViewGL.prototype.add = function (node3D) {
    this.rootNode.add(node3D);
};
ViewGL.prototype.remove = function (node3D) {
    this.rootNode.remove(node3D);
};
ViewGL.prototype.removeAll = function (node3D) {
    this.rootNode.removeAll(node3D);
};

Object.assign(ViewGL.prototype, mixin_notifier);

/* harmony default export */ const core_ViewGL = (ViewGL);
;// CONCATENATED MODULE: ./src/coord/grid3DCreator.js







function resizeCartesian3D(grid3DModel, api) {
    // Use left/top/width/height
    var boxLayoutOption = grid3DModel.getBoxLayoutParams();

    var viewport = getLayoutRect(boxLayoutOption, {
        width: api.getWidth(),
        height: api.getHeight()
    });

    // Flip Y
    viewport.y = api.getHeight() - viewport.y - viewport.height;

    this.viewGL.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, api.getDevicePixelRatio());

    var boxWidth = grid3DModel.get('boxWidth');
    var boxHeight = grid3DModel.get('boxHeight');
    var boxDepth = grid3DModel.get('boxDepth');

    if (true) {
        ['x', 'y', 'z'].forEach(function (dim) {
            if (!this.getAxis(dim)) {
                throw new Error('Grid' + grid3DModel.id + ' don\'t have ' + dim + 'Axis');
            }
        }, this);
    }
    this.getAxis('x').setExtent(-boxWidth / 2, boxWidth / 2);
    // From near to far
    this.getAxis('y').setExtent(boxDepth / 2, -boxDepth / 2);
    this.getAxis('z').setExtent(-boxHeight / 2, boxHeight / 2);

    this.size = [boxWidth, boxHeight, boxDepth];
}

function updateCartesian3D(ecModel, api) {
    var dataExtents = {};
    function unionDataExtents(dim, extent) {
        dataExtents[dim] = dataExtents[dim] || [Infinity, -Infinity];
        dataExtents[dim][0] = Math.min(extent[0], dataExtents[dim][0]);
        dataExtents[dim][1] = Math.max(extent[1], dataExtents[dim][1]);
    }
    // Get data extents for scale.
    ecModel.eachSeries(function (seriesModel) {
        if (seriesModel.coordinateSystem !== this) {
            return;
        }
        var data = seriesModel.getData();
        ['x', 'y', 'z'].forEach(function (coordDim) {
            data.mapDimensionsAll(coordDim, true).forEach(function (dataDim) {
                unionDataExtents(
                    coordDim, data.getDataExtent(dataDim, true)
                );
            });
        });
    }, this);

    ['xAxis3D', 'yAxis3D', 'zAxis3D'].forEach(function (axisType) {
        ecModel.eachComponent(axisType, function (axisModel) {
            var dim = axisType.charAt(0);
            var grid3DModel = axisModel.getReferringComponents('grid3D').models[0];

            var cartesian3D = grid3DModel.coordinateSystem;
            if (cartesian3D !== this) {
                return;
            }

            var axis = cartesian3D.getAxis(dim);
            if (axis) {
                if (true) {
                    console.warn('Can\'t have two %s in one grid3D', axisType);
                }
                return;
            }
            var scale = external_echarts_.helper.createScale(
                dataExtents[dim] || [Infinity, -Infinity], axisModel
            );
            axis = new grid3D_Axis3D(dim, scale);
            axis.type = axisModel.get('type');
            var isCategory = axis.type === 'category';
            axis.onBand = isCategory && axisModel.get('boundaryGap');
            axis.inverse = axisModel.get('inverse');

            axisModel.axis = axis;
            axis.model = axisModel;

            // override `echarts/coord/Axis#getLabelModel`
            axis.getLabelModel = function () {
                return axisModel.getModel('axisLabel', grid3DModel.getModel('axisLabel'));
            };
            // override `echarts/coord/Axis#getTickModel`
            axis.getTickModel = function () {
                return axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));
            };

            cartesian3D.addAxis(axis);
        }, this);
    }, this);

    this.resize(this.model, api);
}

var grid3DCreator = {

    dimensions: grid3D_Cartesian3D.prototype.dimensions,

    create: function (ecModel, api) {

        var cartesian3DList = [];

        ecModel.eachComponent('grid3D', function (grid3DModel) {
            // FIXME
            grid3DModel.__viewGL = grid3DModel.__viewGL || new core_ViewGL();

            var cartesian3D = new grid3D_Cartesian3D();
            cartesian3D.model = grid3DModel;
            cartesian3D.viewGL = grid3DModel.__viewGL;

            grid3DModel.coordinateSystem = cartesian3D;
            cartesian3DList.push(cartesian3D);

            // Inject resize and update
            cartesian3D.resize = resizeCartesian3D;

            cartesian3D.update = updateCartesian3D;
        });

        var axesTypes = ['xAxis3D', 'yAxis3D', 'zAxis3D'];
        function findAxesModels(seriesModel, ecModel) {
            return axesTypes.map(function (axisType) {
                var axisModel = seriesModel.getReferringComponents(axisType).models[0];
                if (axisModel == null) {
                    axisModel = ecModel.getComponent(axisType);
                }
                if (true) {
                    if (!axisModel) {
                        throw new Error(axisType + ' "' + util_retrieve.firstNotNull(
                            seriesModel.get(axisType + 'Index'),
                            seriesModel.get(axisType + 'Id'),
                            0
                        ) + '" not found');
                    }
                }
                return axisModel;
            });
        }

        ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.get('coordinateSystem') !== 'cartesian3D') {
                return;
            }
            var firstGridModel = seriesModel.getReferringComponents('grid3D').models[0];

            if (firstGridModel == null) {
                var axesModels = findAxesModels(seriesModel, ecModel);
                var firstGridModel = axesModels[0].getCoordSysModel();
                axesModels.forEach(function (axisModel) {
                    var grid3DModel = axisModel.getCoordSysModel();
                    if (true) {
                        if (!grid3DModel) {
                            throw new Error(
                                'grid3D "' + util_retrieve.firstNotNull(
                                    axisModel.get('gridIndex'),
                                    axisModel.get('gridId'),
                                    0
                                ) + '" not found'
                            );
                        }
                        if (grid3DModel !== firstGridModel) {
                            throw new Error('xAxis3D, yAxis3D, zAxis3D must use the same grid');
                        }
                    }
                });
            }

            var coordSys = firstGridModel.coordinateSystem;
            seriesModel.coordinateSystem = coordSys;
        });

        return cartesian3DList;
    }
};

/* harmony default export */ const coord_grid3DCreator = (grid3DCreator);
;// CONCATENATED MODULE: ./src/component/grid3D/Axis3DModel.js


var Axis3DModel = external_echarts_.ComponentModel.extend({

    type: 'cartesian3DAxis',

    axis: null,

    /**
     * @override
     */
    getCoordSysModel: function () {
        return this.ecModel.queryComponents({
            mainType: 'grid3D',
            index: this.option.gridIndex,
            id: this.option.gridId
        })[0];
    }
});

external_echarts_.helper.mixinAxisModelCommonMethods(Axis3DModel);

/* harmony default export */ const grid3D_Axis3DModel = (Axis3DModel);
;// CONCATENATED MODULE: ./src/component/grid3D/axis3DDefault.js


var defaultOption = {
    show: true,

    grid3DIndex: 0,
    // 反向坐标轴
    inverse: false,

    // 坐标轴名字
    name: '',
    // 坐标轴名字位置
    nameLocation: 'middle',

    nameTextStyle: {
        fontSize: 16
    },
    // 文字与轴线距离
    nameGap: 20,

    axisPointer: {},

    axisLine: {},
    // 坐标轴小标记
    axisTick: {},
    axisLabel: {},
    // 分隔区域
    splitArea: {}
};

var categoryAxis = external_echarts_.util.merge({
    // 类目起始和结束两端空白策略
    boundaryGap: true,
    // splitArea: {
        // show: false
    // },
    // 坐标轴小标记
    axisTick: {
        // If tick is align with label when boundaryGap is true
        // Default with axisTick
        alignWithLabel: false,
        interval: 'auto'
    },
    // 坐标轴文本标签，详见axis.axisLabel
    axisLabel: {
        interval: 'auto'
    },
    axisPointer: {
        label: {
            show: false
        }
    }
}, defaultOption);

var valueAxis = external_echarts_.util.merge({
    // 数值起始和结束两端空白策略
    boundaryGap: [0, 0],
    // 最小值, 设置成 'dataMin' 则从数据中计算最小值
    // min: null,
    // 最大值，设置成 'dataMax' 则从数据中计算最大值
    // max: null,
    // 脱离0值比例，放大聚焦到最终_min，_max区间
    // scale: false,
    // 分割段数，默认为5
    splitNumber: 5,
    // Minimum interval
    // minInterval: null

    axisPointer: {
        label: {
        }
    }
}, defaultOption);

// FIXME
var timeAxis = external_echarts_.util.defaults({
    scale: true,
    min: 'dataMin',
    max: 'dataMax'
}, valueAxis);
var logAxis = external_echarts_.util.defaults({
    logBase: 10
}, valueAxis);
logAxis.scale = true;

/* harmony default export */ const axis3DDefault = ({
    categoryAxis3D: categoryAxis,
    valueAxis3D: valueAxis,
    timeAxis3D: timeAxis,
    logAxis3D: logAxis
});
;// CONCATENATED MODULE: ./node_modules/echarts/lib/data/OrdinalMeta.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


var OrdinalMeta =
/** @class */
function () {
  function OrdinalMeta(opt) {
    this.categories = opt.categories || [];
    this._needCollect = opt.needCollect;
    this._deduplication = opt.deduplication;
  }

  OrdinalMeta.createByAxisModel = function (axisModel) {
    var option = axisModel.option;
    var data = option.data;
    var categories = data && map(data, getName);
    return new OrdinalMeta({
      categories: categories,
      needCollect: !categories,
      // deduplication is default in axis.
      deduplication: option.dedplication !== false
    });
  };

  ;

  OrdinalMeta.prototype.getOrdinal = function (category) {
    // @ts-ignore
    return this._getOrCreateMap().get(category);
  };
  /**
   * @return The ordinal. If not found, return NaN.
   */


  OrdinalMeta.prototype.parseAndCollect = function (category) {
    var index;
    var needCollect = this._needCollect; // The value of category dim can be the index of the given category set.
    // This feature is only supported when !needCollect, because we should
    // consider a common case: a value is 2017, which is a number but is
    // expected to be tread as a category. This case usually happen in dataset,
    // where it happent to be no need of the index feature.

    if (typeof category !== 'string' && !needCollect) {
      return category;
    } // Optimize for the scenario:
    // category is ['2012-01-01', '2012-01-02', ...], where the input
    // data has been ensured not duplicate and is large data.
    // Notice, if a dataset dimension provide categroies, usually echarts
    // should remove duplication except user tell echarts dont do that
    // (set axis.deduplication = false), because echarts do not know whether
    // the values in the category dimension has duplication (consider the
    // parallel-aqi example)


    if (needCollect && !this._deduplication) {
      index = this.categories.length;
      this.categories[index] = category;
      return index;
    }

    var map = this._getOrCreateMap(); // @ts-ignore


    index = map.get(category);

    if (index == null) {
      if (needCollect) {
        index = this.categories.length;
        this.categories[index] = category; // @ts-ignore

        map.set(category, index);
      } else {
        index = NaN;
      }
    }

    return index;
  }; // Consider big data, do not create map until needed.


  OrdinalMeta.prototype._getOrCreateMap = function () {
    return this._map || (this._map = createHashMap(this.categories));
  };

  return OrdinalMeta;
}();

function getName(obj) {
  if (isObject(obj) && obj.value != null) {
    return obj.value;
  } else {
    return obj + '';
  }
}

/* harmony default export */ const data_OrdinalMeta = (OrdinalMeta);
;// CONCATENATED MODULE: ./src/component/grid3D/createAxis3DModel.js





var AXIS_TYPES = ['value', 'category', 'time', 'log'];
/**
 * Generate sub axis model class
 * @param {} registers
 * @param {string} dim 'x' 'y' 'radius' 'angle' 'parallel'
 * @param {module:echarts/model/Component} BaseAxisModelClass
 * @param {Function} axisTypeDefaulter
 * @param {Object} [extraDefaultOption]
 */
/* harmony default export */ function createAxis3DModel(registers, dim, BaseAxisModelClass, axisTypeDefaulter, extraDefaultOption) {

    AXIS_TYPES.forEach(function (axisType) {

        var AxisModel = BaseAxisModelClass.extend({

            type: dim + 'Axis3D.' + axisType,

            /**
             * @type readOnly
             */
            __ordinalMeta: null,

            mergeDefaultAndTheme: function (option, ecModel) {

                var themeModel = ecModel.getTheme();
                external_echarts_.util.merge(option, themeModel.get(axisType + 'Axis3D'));
                external_echarts_.util.merge(option, this.getDefaultOption());

                option.type = axisTypeDefaulter(dim, option);
            },

            /**
             * @override
             */
            optionUpdated: function () {
                var thisOption = this.option;

                if (thisOption.type === 'category') {
                    this.__ordinalMeta = data_OrdinalMeta.createByAxisModel(this);
                }
            },

            getCategories: function () {
                if (this.option.type === 'category') {
                    return this.__ordinalMeta.categories;
                }
            },

            getOrdinalMeta: function () {
                return this.__ordinalMeta;
            },

            defaultOption: external_echarts_.util.merge(
                external_echarts_.util.clone(axis3DDefault[axisType + 'Axis3D']),
                extraDefaultOption || {},
                true
            )
        });

        registers.registerComponentModel(AxisModel);
    });

    // TODO
    registers.registerSubTypeDefaulter(
        dim + 'Axis3D',
        external_echarts_.util.curry(axisTypeDefaulter, dim)
    );
};
;// CONCATENATED MODULE: ./src/component/grid3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.









function getAxisType(axisDim, option) {
    // Default axis with data is category axis
    return option.type || (option.data ? 'category' : 'value');
}
function install(registers) {
    registers.registerComponentModel(grid3D_Grid3DModel);
    registers.registerComponentView(Grid3DView);

    registers.registerCoordinateSystem('grid3D', coord_grid3DCreator);


    ['x', 'y', 'z'].forEach(function (dim) {
        createAxis3DModel(registers, dim, grid3D_Axis3DModel, getAxisType, {
            name: dim.toUpperCase()
        });
        const AxisView = registers.ComponentView.extend({
            type: dim + 'Axis3D'
        });
        registers.registerComponentView(AxisView);
    });


    registers.registerAction({
        type: 'grid3DChangeCamera',
        event: 'grid3dcamerachanged',
        update: 'series:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'grid3D', query: payload
        }, function (componentModel) {
            componentModel.setView(payload);
        });
    });

    registers.registerAction({
        type: 'grid3DShowAxisPointer',
        event: 'grid3dshowaxispointer',
        update: 'grid3D:showAxisPointer'
    }, function (payload, ecModel) {
    });

    registers.registerAction({
        type: 'grid3DHideAxisPointer',
        event: 'grid3dhideaxispointer',
        update: 'grid3D:hideAxisPointer'
    }, function (payload, ecModel) {
    });
}


;// CONCATENATED MODULE: ./src/component/grid3D.js


(0,external_echarts_.use)(install);
;// CONCATENATED MODULE: ./src/component/common/componentShadingMixin.js
/* harmony default export */ const componentShadingMixin = ({
    defaultOption: {
        shading: null,

        realisticMaterial: {
            textureTiling: 1,
            textureOffset: 0,

            detailTexture: null
        },

        lambertMaterial: {
            textureTiling: 1,
            textureOffset: 0,

            detailTexture: null
        },

        colorMaterial: {
            textureTiling: 1,
            textureOffset: 0,

            detailTexture: null
        },

        hatchingMaterial: {
            textureTiling: 1,
            textureOffset: 0,

            paperColor: '#fff'
        }
    }
});
;// CONCATENATED MODULE: ./src/coord/geo3D/geo3DModelMixin.js


/* harmony default export */ const geo3DModelMixin = ({

    getFilledRegions: function (regions, mapData) {
        var regionsArr = (regions || []).slice();

        var geoJson;
        if (typeof mapData === 'string') {
            mapData = external_echarts_.getMap(mapData);
            geoJson = mapData && mapData.geoJson;
        }
        else {
            if (mapData && mapData.features) {
                geoJson = mapData;
            }
        }
        if (!geoJson) {
            if (true) {
                console.error('Map ' + mapData + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html');
                if (!geoJson.features) {
                    console.error('Invalid GeoJSON for map3D');
                }
            }
            return [];
        }

        var dataNameMap = {};
        var features = geoJson.features;
        for (var i = 0; i < regionsArr.length; i++) {
            dataNameMap[regionsArr[i].name] = regionsArr[i];
        }

        for (var i = 0; i < features.length; i++) {
            var name = features[i].properties.name;
            if (!dataNameMap[name]) {
                regionsArr.push({
                    name: name
                });
            }
        }

        return regionsArr;
    },

    defaultOption: {
        show: true,

        zlevel: -10,

        // geoJson used by geo3D
        map: '',

        // Layout used for viewport
        left: 0,
        top: 0,
        width: '100%',
        height: '100%',

        boxWidth: 100,
        boxHeight: 10,
        boxDepth: 'auto',

        regionHeight: 3,

        environment: 'auto',

        groundPlane: {
            show: false,
            color: '#aaa'
        },

        shading: 'lambert',

        light: {
            main: {
                alpha: 40,
                beta: 30
            }
        },

        viewControl: {
            alpha: 40,
            beta: 0,
            distance: 100,
            orthographicSize: 60,

            minAlpha: 5,
            minBeta: -80,
            maxBeta: 80
        },

        label: {
            show: false,
            // Distance in 3d space.
            distance: 2,

            textStyle: {
                fontSize: 20,
                color: '#000',
                backgroundColor: 'rgba(255,255,255,0.7)',
                padding: 3,
                borderRadius: 4
            }
        },

        // TODO
        // altitude: {
        //     min: 'auto',
        //     max: 'auto',

        //     height: []
        // },


        // labelLine

        // light
        // postEffect
        // temporalSuperSampling

        itemStyle: {
            color: '#fff',
            borderWidth: 0,
            borderColor: '#333'
        },

        emphasis: {
            itemStyle: {
                // color: '#f94b59'
                color: '#639fc0'
            },
            label: {
                show: true
            }
        }
    }
});
;// CONCATENATED MODULE: ./src/component/geo3D/Geo3DModel.js







var Geo3DModel = external_echarts_.ComponentModel.extend({

    type: 'geo3D',

    layoutMode: 'box',

    coordinateSystem: null,

    optionUpdated: function () {
        var option = this.option;

        option.regions = this.getFilledRegions(option.regions, option.map);

        var dimensions = external_echarts_.helper.createDimensions(option.data || [], {
            coordDimensions: ['value'],
            encodeDefine: this.get('encode'),
            dimensionsDefine: this.get('dimensions')
        });
        var list = new external_echarts_.List(dimensions, this);
        list.initData(option.regions);

        var regionModelMap = {};
        list.each(function (idx) {
            var name = list.getName(idx);
            var itemModel = list.getItemModel(idx);
            regionModelMap[name] = itemModel;
        });

        this._regionModelMap = regionModelMap;

        this._data = list;
    },

    getData: function () {
        return this._data;
    },

    getRegionModel: function (idx) {
        var name = this.getData().getName(idx);
        return this._regionModelMap[name] || new external_echarts_.Model(null, this);
    },

    getRegionPolygonCoords: function (idx) {
        var name = this.getData().getName(idx);
        var region = this.coordinateSystem.getRegion(name);

        return region ? region.geometries : [];
    },

    /**
     * Format label
     * @param {string} name Region name
     * @param {string} [status='normal'] 'normal' or 'emphasis'
     * @return {string}
     */
    getFormattedLabel: function (dataIndex, status) {
        var name = this._data.getName(dataIndex);
        var regionModel = this.getRegionModel(dataIndex);
        var formatter = regionModel.get(status === 'normal' ? ['label', 'formatter'] : ['emphasis', 'label', 'formatter']);
        if (formatter == null) {
            formatter = regionModel.get(['label', 'formatter']);
        }
        var params = {
            name: name
        };
        if (typeof formatter === 'function') {
            params.status = status;
            return formatter(params);
        }
        else if (typeof formatter === 'string') {
            var serName = params.seriesName;
            return formatter.replace('{a}', serName != null ? serName : '');
        }
        else {
            return name;
        }
    },

    defaultOption: {

        // itemStyle: {},
        // height,
        // label: {}
        // realisticMaterial
        regions: []
    }
});

external_echarts_.util.merge(Geo3DModel.prototype, geo3DModelMixin);

external_echarts_.util.merge(Geo3DModel.prototype, componentViewControlMixin);
external_echarts_.util.merge(Geo3DModel.prototype, componentPostEffectMixin);
external_echarts_.util.merge(Geo3DModel.prototype, componentLightMixin);
external_echarts_.util.merge(Geo3DModel.prototype, componentShadingMixin);

/* harmony default export */ const geo3D_Geo3DModel = (Geo3DModel);
;// CONCATENATED MODULE: ./src/util/earcut.js
// https://github.com/mapbox/earcut/blob/master/src/earcut.js

/* harmony default export */ const earcut = (earcut_earcut);

function earcut_earcut(data, holeIndices, dim) {

    dim = dim || 2;

    var hasHoles = holeIndices && holeIndices.length,
        outerLen = hasHoles ? holeIndices[0] * dim : data.length,
        outerNode = linkedList(data, 0, outerLen, dim, true),
        triangles = [];

    if (!outerNode) return triangles;

    var minX, minY, maxX, maxY, x, y, size;

    if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);

    // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox
    if (data.length > 80 * dim) {
        minX = maxX = data[0];
        minY = maxY = data[1];

        for (var i = dim; i < outerLen; i += dim) {
            x = data[i];
            y = data[i + 1];
            if (x < minX) minX = x;
            if (y < minY) minY = y;
            if (x > maxX) maxX = x;
            if (y > maxY) maxY = y;
        }

        // minX, minY and size are later used to transform coords into integers for z-order calculation
        size = Math.max(maxX - minX, maxY - minY);
    }

    earcutLinked(outerNode, triangles, dim, minX, minY, size);

    return triangles;
}

// create a circular doubly linked list from polygon points in the specified winding order
function linkedList(data, start, end, dim, clockwise) {
    var i, last;

    if (clockwise === (signedArea(data, start, end, dim) > 0)) {
        for (i = start; i < end; i += dim) last = insertNode(i, data[i], data[i + 1], last);
    } else {
        for (i = end - dim; i >= start; i -= dim) last = insertNode(i, data[i], data[i + 1], last);
    }

    if (last && equals(last, last.next)) {
        removeNode(last);
        last = last.next;
    }

    return last;
}

// eliminate colinear or duplicate points
function filterPoints(start, end) {
    if (!start) return start;
    if (!end) end = start;

    var p = start,
        again;
    do {
        again = false;

        if (!p.steiner && (equals(p, p.next) || earcut_area(p.prev, p, p.next) === 0)) {
            removeNode(p);
            p = end = p.prev;
            if (p === p.next) return null;
            again = true;

        } else {
            p = p.next;
        }
    } while (again || p !== end);

    return end;
}

// main ear slicing loop which triangulates a polygon (given as a linked list)
function earcutLinked(ear, triangles, dim, minX, minY, size, pass) {
    if (!ear) return;

    // interlink polygon nodes in z-order
    if (!pass && size) indexCurve(ear, minX, minY, size);

    var stop = ear,
        prev, next;

    // iterate through ears, slicing them one by one
    while (ear.prev !== ear.next) {
        prev = ear.prev;
        next = ear.next;

        if (size ? isEarHashed(ear, minX, minY, size) : isEar(ear)) {
            // cut off the triangle
            triangles.push(prev.i / dim);
            triangles.push(ear.i / dim);
            triangles.push(next.i / dim);

            removeNode(ear);

            // skipping the next vertice leads to less sliver triangles
            ear = next.next;
            stop = next.next;

            continue;
        }

        ear = next;

        // if we looped through the whole remaining polygon and can't find any more ears
        if (ear === stop) {
            // try filtering points and slicing again
            if (!pass) {
                earcutLinked(filterPoints(ear), triangles, dim, minX, minY, size, 1);

            // if this didn't work, try curing all small self-intersections locally
            } else if (pass === 1) {
                ear = cureLocalIntersections(ear, triangles, dim);
                earcutLinked(ear, triangles, dim, minX, minY, size, 2);

            // as a last resort, try splitting the remaining polygon into two
            } else if (pass === 2) {
                splitEarcut(ear, triangles, dim, minX, minY, size);
            }

            break;
        }
    }
}

// check whether a polygon node forms a valid ear with adjacent nodes
function isEar(ear) {
    var a = ear.prev,
        b = ear,
        c = ear.next;

    if (earcut_area(a, b, c) >= 0) return false; // reflex, can't be an ear

    // now make sure we don't have other points inside the potential ear
    var p = ear.next.next;

    while (p !== ear.prev) {
        if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            earcut_area(p.prev, p, p.next) >= 0) return false;
        p = p.next;
    }

    return true;
}

function isEarHashed(ear, minX, minY, size) {
    var a = ear.prev,
        b = ear,
        c = ear.next;

    if (earcut_area(a, b, c) >= 0) return false; // reflex, can't be an ear

    // triangle bbox; min & max are calculated like this for speed
    var minTX = a.x < b.x ? (a.x < c.x ? a.x : c.x) : (b.x < c.x ? b.x : c.x),
        minTY = a.y < b.y ? (a.y < c.y ? a.y : c.y) : (b.y < c.y ? b.y : c.y),
        maxTX = a.x > b.x ? (a.x > c.x ? a.x : c.x) : (b.x > c.x ? b.x : c.x),
        maxTY = a.y > b.y ? (a.y > c.y ? a.y : c.y) : (b.y > c.y ? b.y : c.y);

    // z-order range for the current triangle bbox;
    var minZ = zOrder(minTX, minTY, minX, minY, size),
        maxZ = zOrder(maxTX, maxTY, minX, minY, size);

    // first look for points inside the triangle in increasing z-order
    var p = ear.nextZ;

    while (p && p.z <= maxZ) {
        if (p !== ear.prev && p !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            earcut_area(p.prev, p, p.next) >= 0) return false;
        p = p.nextZ;
    }

    // then look for points in decreasing z-order
    p = ear.prevZ;

    while (p && p.z >= minZ) {
        if (p !== ear.prev && p !== ear.next &&
            pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) &&
            earcut_area(p.prev, p, p.next) >= 0) return false;
        p = p.prevZ;
    }

    return true;
}

// go through all polygon nodes and cure small local self-intersections
function cureLocalIntersections(start, triangles, dim) {
    var p = start;
    do {
        var a = p.prev,
            b = p.next.next;

        if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {

            triangles.push(a.i / dim);
            triangles.push(p.i / dim);
            triangles.push(b.i / dim);

            // remove two nodes involved
            removeNode(p);
            removeNode(p.next);

            p = start = b;
        }
        p = p.next;
    } while (p !== start);

    return p;
}

// try splitting polygon into two and triangulate them independently
function splitEarcut(start, triangles, dim, minX, minY, size) {
    // look for a valid diagonal that divides the polygon into two
    var a = start;
    do {
        var b = a.next.next;
        while (b !== a.prev) {
            if (a.i !== b.i && isValidDiagonal(a, b)) {
                // split the polygon in two by the diagonal
                var c = splitPolygon(a, b);

                // filter colinear points around the cuts
                a = filterPoints(a, a.next);
                c = filterPoints(c, c.next);

                // run earcut on each half
                earcutLinked(a, triangles, dim, minX, minY, size);
                earcutLinked(c, triangles, dim, minX, minY, size);
                return;
            }
            b = b.next;
        }
        a = a.next;
    } while (a !== start);
}

// link every hole into the outer loop, producing a single-ring polygon without holes
function eliminateHoles(data, holeIndices, outerNode, dim) {
    var queue = [],
        i, len, start, end, list;

    for (i = 0, len = holeIndices.length; i < len; i++) {
        start = holeIndices[i] * dim;
        end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
        list = linkedList(data, start, end, dim, false);
        if (list === list.next) list.steiner = true;
        queue.push(getLeftmost(list));
    }

    queue.sort(compareX);

    // process holes from left to right
    for (i = 0; i < queue.length; i++) {
        eliminateHole(queue[i], outerNode);
        outerNode = filterPoints(outerNode, outerNode.next);
    }

    return outerNode;
}

function compareX(a, b) {
    return a.x - b.x;
}

// find a bridge between vertices that connects hole with an outer ring and and link it
function eliminateHole(hole, outerNode) {
    outerNode = findHoleBridge(hole, outerNode);
    if (outerNode) {
        var b = splitPolygon(outerNode, hole);
        filterPoints(b, b.next);
    }
}

// David Eberly's algorithm for finding a bridge between hole and outer polygon
function findHoleBridge(hole, outerNode) {
    var p = outerNode,
        hx = hole.x,
        hy = hole.y,
        qx = -Infinity,
        m;

    // find a segment intersected by a ray from the hole's leftmost point to the left;
    // segment's endpoint with lesser x will be potential connection point
    do {
        if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
            var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
            if (x <= hx && x > qx) {
                qx = x;
                if (x === hx) {
                    if (hy === p.y) return p;
                    if (hy === p.next.y) return p.next;
                }
                m = p.x < p.next.x ? p : p.next;
            }
        }
        p = p.next;
    } while (p !== outerNode);

    if (!m) return null;

    if (hx === qx) return m.prev; // hole touches outer segment; pick lower endpoint

    // look for points inside the triangle of hole point, segment intersection and endpoint;
    // if there are no points found, we have a valid connection;
    // otherwise choose the point of the minimum angle with the ray as connection point

    var stop = m,
        mx = m.x,
        my = m.y,
        tanMin = Infinity,
        tan;

    p = m.next;

    while (p !== stop) {
        if (hx >= p.x && p.x >= mx && hx !== p.x &&
                pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {

            tan = Math.abs(hy - p.y) / (hx - p.x); // tangential

            if ((tan < tanMin || (tan === tanMin && p.x > m.x)) && locallyInside(p, hole)) {
                m = p;
                tanMin = tan;
            }
        }

        p = p.next;
    }

    return m;
}

// interlink polygon nodes in z-order
function indexCurve(start, minX, minY, size) {
    var p = start;
    do {
        if (p.z === null) p.z = zOrder(p.x, p.y, minX, minY, size);
        p.prevZ = p.prev;
        p.nextZ = p.next;
        p = p.next;
    } while (p !== start);

    p.prevZ.nextZ = null;
    p.prevZ = null;

    sortLinked(p);
}

// Simon Tatham's linked list merge sort algorithm
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
function sortLinked(list) {
    var i, p, q, e, tail, numMerges, pSize, qSize,
        inSize = 1;

    do {
        p = list;
        list = null;
        tail = null;
        numMerges = 0;

        while (p) {
            numMerges++;
            q = p;
            pSize = 0;
            for (i = 0; i < inSize; i++) {
                pSize++;
                q = q.nextZ;
                if (!q) break;
            }
            qSize = inSize;

            while (pSize > 0 || (qSize > 0 && q)) {

                if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
                    e = p;
                    p = p.nextZ;
                    pSize--;
                } else {
                    e = q;
                    q = q.nextZ;
                    qSize--;
                }

                if (tail) tail.nextZ = e;
                else list = e;

                e.prevZ = tail;
                tail = e;
            }

            p = q;
        }

        tail.nextZ = null;
        inSize *= 2;

    } while (numMerges > 1);

    return list;
}

// z-order of a point given coords and size of the data bounding box
function zOrder(x, y, minX, minY, size) {
    // coords are transformed into non-negative 15-bit integer range
    x = 32767 * (x - minX) / size;
    y = 32767 * (y - minY) / size;

    x = (x | (x << 8)) & 0x00FF00FF;
    x = (x | (x << 4)) & 0x0F0F0F0F;
    x = (x | (x << 2)) & 0x33333333;
    x = (x | (x << 1)) & 0x55555555;

    y = (y | (y << 8)) & 0x00FF00FF;
    y = (y | (y << 4)) & 0x0F0F0F0F;
    y = (y | (y << 2)) & 0x33333333;
    y = (y | (y << 1)) & 0x55555555;

    return x | (y << 1);
}

// find the leftmost node of a polygon ring
function getLeftmost(start) {
    var p = start,
        leftmost = start;
    do {
        if (p.x < leftmost.x) leftmost = p;
        p = p.next;
    } while (p !== start);

    return leftmost;
}

// check if a point lies within a convex triangle
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
    return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 &&
           (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 &&
           (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
}

// check if a diagonal between two polygon nodes is valid (lies in polygon interior)
function isValidDiagonal(a, b) {
    return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) &&
           locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b);
}

// signed area of a triangle
function earcut_area(p, q, r) {
    return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
}

// check if two points are equal
function equals(p1, p2) {
    return p1.x === p2.x && p1.y === p2.y;
}

// check if two segments intersect
function intersects(p1, q1, p2, q2) {
    if ((equals(p1, q1) && equals(p2, q2)) ||
        (equals(p1, q2) && equals(p2, q1))) return true;
    return earcut_area(p1, q1, p2) > 0 !== earcut_area(p1, q1, q2) > 0 &&
           earcut_area(p2, q2, p1) > 0 !== earcut_area(p2, q2, q1) > 0;
}

// check if a polygon diagonal intersects any polygon segments
function intersectsPolygon(a, b) {
    var p = a;
    do {
        if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&
                intersects(p, p.next, a, b)) return true;
        p = p.next;
    } while (p !== a);

    return false;
}

// check if a polygon diagonal is locally inside the polygon
function locallyInside(a, b) {
    return earcut_area(a.prev, a, a.next) < 0 ?
        earcut_area(a, b, a.next) >= 0 && earcut_area(a, a.prev, b) >= 0 :
        earcut_area(a, b, a.prev) < 0 || earcut_area(a, a.next, b) < 0;
}

// check if the middle point of a polygon diagonal is inside the polygon
function middleInside(a, b) {
    var p = a,
        inside = false,
        px = (a.x + b.x) / 2,
        py = (a.y + b.y) / 2;
    do {
        if (((p.y > py) !== (p.next.y > py)) && p.next.y !== p.y &&
                (px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x))
            inside = !inside;
        p = p.next;
    } while (p !== a);

    return inside;
}

// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;
// if one belongs to the outer ring and another to a hole, it merges it into a single ring
function splitPolygon(a, b) {
    var a2 = new earcut_Node(a.i, a.x, a.y),
        b2 = new earcut_Node(b.i, b.x, b.y),
        an = a.next,
        bp = b.prev;

    a.next = b;
    b.prev = a;

    a2.next = an;
    an.prev = a2;

    b2.next = a2;
    a2.prev = b2;

    bp.next = b2;
    b2.prev = bp;

    return b2;
}

// create a node and optionally link it with previous one (in a circular doubly linked list)
function insertNode(i, x, y, last) {
    var p = new earcut_Node(i, x, y);

    if (!last) {
        p.prev = p;
        p.next = p;

    } else {
        p.next = last.next;
        p.prev = last;
        last.next.prev = p;
        last.next = p;
    }
    return p;
}

function removeNode(p) {
    p.next.prev = p.prev;
    p.prev.next = p.next;

    if (p.prevZ) p.prevZ.nextZ = p.nextZ;
    if (p.nextZ) p.nextZ.prevZ = p.prevZ;
}

function earcut_Node(i, x, y) {
    // vertice index in coordinates array
    this.i = i;

    // vertex coordinates
    this.x = x;
    this.y = y;

    // previous and next vertice nodes in a polygon ring
    this.prev = null;
    this.next = null;

    // z-order curve value
    this.z = null;

    // previous and next nodes in z-order
    this.prevZ = null;
    this.nextZ = null;

    // indicates whether this is a steiner point
    this.steiner = false;
}

// return a percentage difference between the polygon area and its triangulation area;
// used to verify correctness of triangulation
earcut_earcut.deviation = function (data, holeIndices, dim, triangles) {
    var hasHoles = holeIndices && holeIndices.length;
    var outerLen = hasHoles ? holeIndices[0] * dim : data.length;

    var polygonArea = Math.abs(signedArea(data, 0, outerLen, dim));
    if (hasHoles) {
        for (var i = 0, len = holeIndices.length; i < len; i++) {
            var start = holeIndices[i] * dim;
            var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
            polygonArea -= Math.abs(signedArea(data, start, end, dim));
        }
    }

    var trianglesArea = 0;
    for (i = 0; i < triangles.length; i += 3) {
        var a = triangles[i] * dim;
        var b = triangles[i + 1] * dim;
        var c = triangles[i + 2] * dim;
        trianglesArea += Math.abs(
            (data[a] - data[c]) * (data[b + 1] - data[a + 1]) -
            (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
    }

    return polygonArea === 0 && trianglesArea === 0 ? 0 :
        Math.abs((trianglesArea - polygonArea) / polygonArea);
};

function signedArea(data, start, end, dim) {
    var sum = 0;
    for (var i = start, j = end - dim; i < end; i += dim) {
        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
        j = i;
    }
    return sum;
}
;// CONCATENATED MODULE: ./src/util/ProgressiveQuickSort.js

function swap(arr, a, b) {
    var tmp = arr[a];
    arr[a] = arr[b];
    arr[b] = tmp;
}
function partition(arr, pivot, left, right, compare) {
    var storeIndex = left;
    var pivotValue = arr[pivot];

    // put the pivot on the right
    swap(arr, pivot, right);

    // go through the rest
    for(var v = left; v < right; v++) {
        if(compare(arr[v], pivotValue) < 0) {
            swap(arr, v, storeIndex);
            storeIndex++;
        }
    }

    // finally put the pivot in the correct place
    swap(arr, right, storeIndex);

    return storeIndex;
}

function quickSort(array, compare, left, right) {
    if(left < right) {
        var pivot = Math.floor((left + right) / 2);
        var newPivot = partition(array, pivot, left, right, compare);
        quickSort(array, compare, left, newPivot - 1);
        quickSort(array, compare, newPivot + 1, right);
    }
}


// TODO Test.
function ProgressiveQuickSort() {

    // this._pivotList = new LinkedList();
    this._parts = [];
}

ProgressiveQuickSort.prototype.step = function (arr, compare, frame) {

    var len = arr.length;
    if (frame === 0) {
        this._parts = [];
        this._sorted = false;

        // Pick a start pivot;
        var pivot = Math.floor(len / 2);
        this._parts.push({
            pivot: pivot,
            left: 0,
            right: len - 1
        });

        this._currentSortPartIdx = 0;
    }

    if (this._sorted) {
        return;
    }

    var parts = this._parts;
    if (parts.length === 0) {
        this._sorted = true;
        // Already finished.
        return true;
    }
    else if (parts.length < 512) {
        // Sort large parts in about 10 frames.
        for (var i = 0; i < parts.length; i++) {
            // Partition and Modify the pivot index.
            parts[i].pivot = partition(
                arr, parts[i].pivot, parts[i].left, parts[i].right, compare
            );
        }

        var subdividedParts = [];
        for (var i = 0; i < parts.length; i++) {
            // Subdivide left
            var left = parts[i].left;
            var right = parts[i].pivot - 1;
            if (right > left) {
                subdividedParts.push({
                    pivot: Math.floor((right + left) / 2),
                    left: left, right: right
                });
            }
            // Subdivide right
            var left = parts[i].pivot + 1;
            var right = parts[i].right;
            if (right > left) {
                subdividedParts.push({
                    pivot: Math.floor((right + left) / 2),
                    left: left, right: right
                });
            }
        }
        parts = this._parts = subdividedParts;
    }
    else {
        // console.time('sort');
        // Finally quick sort each parts in 10 frames.
        for (var i = 0; i < Math.floor(parts.length / 10); i++) {
            // Sort near parts first.
            var idx = parts.length - 1 - this._currentSortPartIdx;
            quickSort(arr, compare, parts[idx].left, parts[idx].right);
            this._currentSortPartIdx++;

            // Finish sort
            if (this._currentSortPartIdx === parts.length) {
                this._sorted = true;
                return true;
            }
        }
        // console.timeEnd('sort');

    }

    return false;
};

ProgressiveQuickSort.sort = quickSort;

/* harmony default export */ const util_ProgressiveQuickSort = (ProgressiveQuickSort);
;// CONCATENATED MODULE: ./src/util/geometry/trianglesSortMixin.js


var trianglesSortMixin_vec3 = dep_glmatrix.vec3;

var p0 = trianglesSortMixin_vec3.create();
var p1 = trianglesSortMixin_vec3.create();
var p2 = trianglesSortMixin_vec3.create();
// var cp = vec3.create();

/* harmony default export */ const trianglesSortMixin = ({

    needsSortTriangles: function () {
        return this.indices && this.sortTriangles;
    },

    needsSortTrianglesProgressively: function () {
        return this.needsSortTriangles() && this.triangleCount >= 2e4;
    },

    doSortTriangles: function (cameraPos, frame) {
        var indices = this.indices;
        // Do progressive quick sort.
        if (frame === 0) {
            var posAttr = this.attributes.position;
            var cameraPos = cameraPos.array;

            if (!this._triangleZList || this._triangleZList.length !== this.triangleCount) {
                this._triangleZList = new Float32Array(this.triangleCount);
                this._sortedTriangleIndices = new Uint32Array(this.triangleCount);

                this._indicesTmp = new indices.constructor(indices.length);
                this._triangleZListTmp = new Float32Array(this.triangleCount);
            }

            var cursor = 0;
            var firstZ;
            for (var i = 0; i < indices.length;) {
                posAttr.get(indices[i++], p0);
                posAttr.get(indices[i++], p1);
                posAttr.get(indices[i++], p2);

                // FIXME If use center ?
                // cp[0] = (p0[0] + p1[0] + p2[0]) / 3;
                // cp[1] = (p0[1] + p1[1] + p2[1]) / 3;
                // cp[2] = (p0[2] + p1[2] + p2[2]) / 3;
                // Camera position is in object space

                // Use max of three points, PENDING
                var z0 = trianglesSortMixin_vec3.sqrDist(p0, cameraPos);
                var z1 = trianglesSortMixin_vec3.sqrDist(p1, cameraPos);
                var z2 = trianglesSortMixin_vec3.sqrDist(p2, cameraPos);
                var zMax = Math.min(z0, z1);
                zMax = Math.min(zMax, z2);
                if (i === 3) {
                    firstZ = zMax;
                    zMax = 0;
                }
                else {
                    // Only store the difference to avoid the precision issue.
                    zMax = zMax - firstZ;
                }
                this._triangleZList[cursor++] = zMax;
            }
        }


        var sortedTriangleIndices = this._sortedTriangleIndices;
        for (var i = 0; i < sortedTriangleIndices.length; i++) {
            sortedTriangleIndices[i] = i;
        }

        if (this.triangleCount < 2e4) {
            // Use simple timsort for simple geometries.
            if (frame === 0) {
                // Use native sort temporary.
                this._simpleSort(true);
            }
        }
        else {
            for (var i = 0; i < 3; i++) {
                this._progressiveQuickSort(frame * 3 + i);
            }
        }

        var targetIndices = this._indicesTmp;
        var targetTriangleZList = this._triangleZListTmp;
        var faceZList = this._triangleZList;
        for (var i = 0; i < this.triangleCount; i++) {
            var fromIdx3 = sortedTriangleIndices[i] * 3;
            var toIdx3 = i * 3;
            targetIndices[toIdx3++] = indices[fromIdx3++];
            targetIndices[toIdx3++] = indices[fromIdx3++];
            targetIndices[toIdx3] = indices[fromIdx3];

            targetTriangleZList[i] = faceZList[sortedTriangleIndices[i]];
        }

        // Swap indices.
        var tmp = this._indicesTmp;
        this._indicesTmp = this.indices;
        this.indices = tmp;
        var tmp = this._triangleZListTmp;
        this._triangleZListTmp = this._triangleZList;
        this._triangleZList = tmp;

        this.dirtyIndices();
    },

    _simpleSort: function (useNativeQuickSort) {
        var faceZList = this._triangleZList;
        var sortedTriangleIndices = this._sortedTriangleIndices;

        function compare(a, b) {
            // Sort from far to near. which is descending order
            return faceZList[b] - faceZList[a];
        }
        if (useNativeQuickSort) {
            Array.prototype.sort.call(sortedTriangleIndices, compare);
        }
        else {
            util_ProgressiveQuickSort.sort(sortedTriangleIndices, compare, 0, sortedTriangleIndices.length - 1);
        }
    },

    _progressiveQuickSort: function (frame) {
        var faceZList = this._triangleZList;
        var sortedTriangleIndices = this._sortedTriangleIndices;

        this._quickSort = this._quickSort || new util_ProgressiveQuickSort();

        this._quickSort.step(sortedTriangleIndices, function (a, b) {
            return faceZList[b] - faceZList[a];
        }, frame);
    }
});
;// CONCATENATED MODULE: ./src/util/visual.js
function getVisualColor(data) {
    const style = data.getVisual('style');
    if (style) {
        const drawType = data.getVisual('drawType');
        return style[drawType];
    }
}
function getVisualOpacity(data) {
    const style = data.getVisual('style');
    return style.opacity;
}
function getItemVisualColor(data, idx) {
    const style = data.getItemVisual(idx, 'style');
    if (style) {
        const drawType = data.getVisual('drawType');
        return style[drawType];
    }
}
function getItemVisualOpacity(data, idx) {
    const style = data.getItemVisual(idx, 'style');
    return style && style.opacity;
}
;// CONCATENATED MODULE: ./src/component/common/LabelsBuilder.js








var LABEL_NORMAL_SHOW_BIT = 1;
var LABEL_EMPHASIS_SHOW_BIT = 2;

function LabelsBuilder(width, height, api) {

    this._labelsMesh = new LabelsMesh();

    this._labelTextureSurface = new util_ZRTextureAtlasSurface({
        width: 512,
        height: 512,
        devicePixelRatio: api.getDevicePixelRatio(),
        onupdate: function () {
            api.getZr().refresh();
        }
    });
    this._api = api;

    this._labelsMesh.material.set('textureAtlas', this._labelTextureSurface.getTexture());
}

LabelsBuilder.prototype.getLabelPosition = function (dataIndex, positionDesc, distance) {
    return [0, 0, 0];
};

LabelsBuilder.prototype.getLabelDistance = function (dataIndex, positionDesc, distance) {
    return 0;
};

LabelsBuilder.prototype.getMesh = function () {
    return this._labelsMesh;
};

LabelsBuilder.prototype.updateData = function (data, start, end) {
    if (start == null) {
        start = 0;
    }
    if (end == null) {
        end = data.count();
    }

    if (!this._labelsVisibilitiesBits || this._labelsVisibilitiesBits.length !== (end - start)) {
        this._labelsVisibilitiesBits = new Uint8Array(end - start);
    }
    var normalLabelVisibilityQuery = ['label', 'show'];
    var emphasisLabelVisibilityQuery = ['emphasis', 'label', 'show'];

    for (var idx = start; idx < end; idx++) {
        var itemModel = data.getItemModel(idx);
        var normalVisibility = itemModel.get(normalLabelVisibilityQuery);
        var emphasisVisibility = itemModel.get(emphasisLabelVisibilityQuery);
        if (emphasisVisibility == null) {
            emphasisVisibility = normalVisibility;
        }
        var bit = (normalVisibility ? LABEL_NORMAL_SHOW_BIT : 0)
            | (emphasisVisibility ? LABEL_EMPHASIS_SHOW_BIT : 0);
        this._labelsVisibilitiesBits[idx - start] = bit;
    }

    this._start = start;
    this._end = end;

    this._data = data;
};

LabelsBuilder.prototype.updateLabels = function (highlightDataIndices) {

    if (!this._data) {
        return;
    }

    highlightDataIndices = highlightDataIndices || [];

    var hasHighlightData = highlightDataIndices.length > 0;
    var highlightDataIndicesMap = {};
    for (var i = 0; i < highlightDataIndices.length; i++) {
        highlightDataIndicesMap[highlightDataIndices[i]] = true;
    }

    this._labelsMesh.geometry.convertToDynamicArray(true);
    this._labelTextureSurface.clear();

    var normalLabelQuery = ['label'];
    var emphasisLabelQuery = ['emphasis', 'label'];
    var seriesModel = this._data.hostModel;
    var data = this._data;

    var seriesLabelModel = seriesModel.getModel(normalLabelQuery);
    var seriesLabelEmphasisModel = seriesModel.getModel(emphasisLabelQuery, seriesLabelModel);

    var textAlignMap = {
        left: 'right',
        right: 'left',
        top: 'center',
        bottom: 'center'
    };
    var textVerticalAlignMap = {
        left: 'middle',
        right: 'middle',
        top: 'bottom',
        bottom: 'top'
    };

    for (var dataIndex = this._start; dataIndex < this._end; dataIndex++) {
        var isEmphasis = false;
        if (hasHighlightData && highlightDataIndicesMap[dataIndex]) {
            isEmphasis = true;
        }
        var ifShow = this._labelsVisibilitiesBits[dataIndex - this._start]
            & (isEmphasis ? LABEL_EMPHASIS_SHOW_BIT : LABEL_NORMAL_SHOW_BIT);
        if (!ifShow) {
            continue;
        }

        var itemModel = data.getItemModel(dataIndex);
        var labelModel = itemModel.getModel(
            isEmphasis ? emphasisLabelQuery : normalLabelQuery,
            isEmphasis ? seriesLabelEmphasisModel : seriesLabelModel
        );
        var distance = labelModel.get('distance') || 0;
        var position = labelModel.get('position');

        var dpr = this._api.getDevicePixelRatio();
        var text = seriesModel.getFormattedLabel(dataIndex, isEmphasis ? 'emphasis' : 'normal');
        if (text == null || text === '') {
            return;
        }

        // TODO Background.
        var textEl = new external_echarts_.graphic.Text({
            style: createTextStyle(labelModel, {
                text: text,
                fill: labelModel.get('color') || getItemVisualColor(data, dataIndex) || '#000',
                align: 'left',
                verticalAlign: 'top',
                opacity: util_retrieve.firstNotNull(labelModel.get('opacity'), getItemVisualOpacity(data, dataIndex), 1)
            })
        });

        var rect = textEl.getBoundingRect();
        var lineHeight = 1.2;
        rect.height *= lineHeight;

        var coords = this._labelTextureSurface.add(textEl);

        var textAlign = textAlignMap[position] || 'center';
        var textVerticalAlign = textVerticalAlignMap[position] || 'bottom';

        this._labelsMesh.geometry.addSprite(
            this.getLabelPosition(dataIndex, position, distance),
            [rect.width * dpr, rect.height * dpr], coords,
            textAlign, textVerticalAlign,
            this.getLabelDistance(dataIndex, position, distance) * dpr
        );
    }

    this._labelsMesh.material.set('uvScale', this._labelTextureSurface.getCoordsScale());

    // var canvas = this._labelTextureSurface.getTexture().image;
    // document.body.appendChild(canvas);
    // canvas.style.cssText = 'position:absolute;z-index: 1000';

    // Update image.
    this._labelTextureSurface.getZr().refreshImmediately();
    this._labelsMesh.geometry.convertToTypedArray();
    this._labelsMesh.geometry.dirty();
};

LabelsBuilder.prototype.dispose = function () {
    this._labelTextureSurface.dispose();
}

/* harmony default export */ const common_LabelsBuilder = (LabelsBuilder);
;// CONCATENATED MODULE: ./src/component/common/Geo3DBuilder.js











var Geo3DBuilder_vec3 = dep_glmatrix.vec3;

util_graphicGL.Shader.import(lines3D_glsl);

function Geo3DBuilder(api) {

    this.rootNode = new util_graphicGL.Node();

    // Cache triangulation result
    this._triangulationResults = {};

    this._shadersMap = util_graphicGL.COMMON_SHADERS.filter(function (shaderName) {
        return shaderName !== 'shadow';
    }).reduce(function (obj, shaderName) {
        obj[shaderName] = util_graphicGL.createShader('ecgl.' + shaderName);
        return obj;
    }, {});

    this._linesShader = util_graphicGL.createShader('ecgl.meshLines3D');

    var groundMaterials = {};
    util_graphicGL.COMMON_SHADERS.forEach(function (shading) {
        groundMaterials[shading] = new util_graphicGL.Material({
            shader: util_graphicGL.createShader('ecgl.' + shading)
        });
    });
    this._groundMaterials = groundMaterials;

    this._groundMesh = new util_graphicGL.Mesh({
        geometry: new util_graphicGL.PlaneGeometry({ dynamic: true }),
        castShadow: false,
        renderNormal: true,
        $ignorePicking: true
    });
    this._groundMesh.rotation.rotateX(-Math.PI / 2);

    this._labelsBuilder = new common_LabelsBuilder(512, 512, api);

    // Give a large render order.
    this._labelsBuilder.getMesh().renderOrder = 100;
    this._labelsBuilder.getMesh().material.depthTest = false;

    this.rootNode.add(this._labelsBuilder.getMesh());

    this._initMeshes();

    this._api = api;
}

Geo3DBuilder.prototype = {

    constructor: Geo3DBuilder,

    // Which dimension to extrude. Y or Z
    extrudeY: true,

    update: function (componentModel, ecModel, api, start, end) {

        var data = componentModel.getData();

        if (start == null) {
            start = 0;
        }
        if (end == null) {
            end = data.count();
        }

        this._startIndex = start;
        this._endIndex = end - 1;

        this._triangulation(componentModel, start, end);

        var shader = this._getShader(componentModel.get('shading'));

        this._prepareMesh(componentModel, shader, api, start, end);

        this.rootNode.updateWorldTransform();

        this._updateRegionMesh(componentModel, api, start, end);

        var coordSys = componentModel.coordinateSystem;
        // PENDING
        if (coordSys.type === 'geo3D') {
            this._updateGroundPlane(componentModel, coordSys, api);
        }

        var self = this;
        this._labelsBuilder.updateData(data, start, end);
        this._labelsBuilder.getLabelPosition = function (dataIndex, positionDesc, distance) {
            var name = data.getName(dataIndex);

            var center;
            var height = distance;
            if (coordSys.type === 'geo3D') {
                var region = coordSys.getRegion(name);
                if (!region) {
                    return [NaN, NaN, NaN];
                }
                center = region.getCenter();
                var pos = coordSys.dataToPoint([center[0], center[1], height]);
                return pos;
            }
            else {
                var tmp = self._triangulationResults[dataIndex - self._startIndex];
                var center = self.extrudeY ? [
                    (tmp.max[0] + tmp.min[0]) / 2,
                    tmp.max[1] + height,
                    (tmp.max[2] + tmp.min[2]) / 2
                ] : [
                    (tmp.max[0] + tmp.min[0]) / 2,
                    (tmp.max[1] + tmp.min[1]) / 2,
                    tmp.max[2] + height
                ];
            }
        };

        this._data = data;

        this._labelsBuilder.updateLabels();

        this._updateDebugWireframe(componentModel);

        // Reset some state.
        this._lastHoverDataIndex = 0;
    },

    _initMeshes: function () {
        var self = this;
        function createPolygonMesh() {
            var mesh = new util_graphicGL.Mesh({
                name: 'Polygon',
                material: new util_graphicGL.Material({
                    shader: self._shadersMap.lambert
                }),
                geometry: new util_graphicGL.Geometry({
                    sortTriangles: true,
                    dynamic: true
                }),
                // TODO Disable culling
                culling: false,
                ignorePicking: true,
                // Render normal in normal pass
                renderNormal: true
            });
            Object.assign(mesh.geometry, trianglesSortMixin);
            return mesh;
        }

        var polygonMesh = createPolygonMesh();

        var linesMesh = new util_graphicGL.Mesh({
            material: new util_graphicGL.Material({
                shader: this._linesShader
            }),
            castShadow: false,
            ignorePicking: true,
            $ignorePicking: true,
            geometry: new Lines3D({
                useNativeLine: false
            })
        });

        this.rootNode.add(polygonMesh);
        this.rootNode.add(linesMesh);

        polygonMesh.material.define('both', 'VERTEX_COLOR');
        polygonMesh.material.define('fragment', 'DOUBLE_SIDED');

        this._polygonMesh = polygonMesh;
        this._linesMesh = linesMesh;

        this.rootNode.add(this._groundMesh);
    },

    _getShader: function (shading) {
        var shader = this._shadersMap[shading];
        if (!shader) {
            if (true) {
                console.warn('Unkown shading ' + shading);
            }
            // Default use lambert shader.
            shader = this._shadersMap.lambert;
        }
        shader.__shading = shading;
        return shader;
    },

    _prepareMesh: function (componentModel, shader, api, start, end) {
        var polygonVertexCount = 0;
        var polygonTriangleCount = 0;
        var linesVertexCount = 0;
        var linesTriangleCount = 0;
        // TODO Lines
        for (var idx = start; idx < end; idx++) {
            var polyInfo = this._getRegionPolygonInfo(idx);
            var lineInfo = this._getRegionLinesInfo(idx, componentModel, this._linesMesh.geometry);
            polygonVertexCount += polyInfo.vertexCount;
            polygonTriangleCount += polyInfo.triangleCount;
            linesVertexCount += lineInfo.vertexCount;
            linesTriangleCount += lineInfo.triangleCount;
        }

        var polygonMesh = this._polygonMesh;
        var polygonGeo = polygonMesh.geometry;
        ['position', 'normal', 'texcoord0', 'color'].forEach(function (attrName) {
            polygonGeo.attributes[attrName].init(polygonVertexCount);
        });
        polygonGeo.indices = polygonVertexCount > 0xffff ? new Uint32Array(polygonTriangleCount * 3) : new Uint16Array(polygonTriangleCount * 3);

        if (polygonMesh.material.shader !== shader) {
            polygonMesh.material.attachShader(shader, true);
        }
        util_graphicGL.setMaterialFromModel(shader.__shading, polygonMesh.material, componentModel, api);

        if (linesVertexCount > 0) {
            this._linesMesh.geometry.resetOffset();
            this._linesMesh.geometry.setVertexCount(linesVertexCount);
            this._linesMesh.geometry.setTriangleCount(linesTriangleCount);
        }

        // Indexing data index from vertex index.
        this._dataIndexOfVertex = new Uint32Array(polygonVertexCount);
        // Indexing vertex index range from data index
        this._vertexRangeOfDataIndex = new Uint32Array((end - start) * 2);
    },

    _updateRegionMesh: function (componentModel, api, start, end) {

        var data = componentModel.getData();

        var vertexOffset = 0;
        var triangleOffset = 0;

        // Materials configurations.
        var hasTranparentRegion = false;

        var polygonMesh = this._polygonMesh;
        var linesMesh = this._linesMesh;

        for (var dataIndex = start; dataIndex < end; dataIndex++) {
            // Get bunch of visual properties.
            var regionModel = componentModel.getRegionModel(dataIndex);
            var itemStyleModel = regionModel.getModel('itemStyle');

            var color = util_retrieve.firstNotNull(
                getItemVisualColor(data, dataIndex),
                itemStyleModel.get('color'),
                '#fff'
            );
            var opacity = util_retrieve.firstNotNull(getItemVisualOpacity(data, dataIndex), 1);

            var colorArr = util_graphicGL.parseColor(color);
            var borderColorArr = util_graphicGL.parseColor(itemStyleModel.get('borderColor'));

            colorArr[3] *= opacity;
            borderColorArr[3] *= opacity;

            var isTransparent = colorArr[3] < 0.99;

            polygonMesh.material.set('color', [1, 1, 1, 1]);
            hasTranparentRegion = hasTranparentRegion || isTransparent;

            var regionHeight = util_retrieve.firstNotNull(regionModel.get('height', true), componentModel.get('regionHeight'));

            var newOffsets = this._updatePolygonGeometry(
                componentModel, polygonMesh.geometry, dataIndex, regionHeight,
                vertexOffset, triangleOffset, colorArr
            );

            for (var i = vertexOffset; i < newOffsets.vertexOffset; i++) {
                this._dataIndexOfVertex[i] = dataIndex;
            }
            this._vertexRangeOfDataIndex[(dataIndex - start) * 2] = vertexOffset;
            this._vertexRangeOfDataIndex[(dataIndex - start) * 2 + 1] = newOffsets.vertexOffset;

            vertexOffset = newOffsets.vertexOffset;
            triangleOffset = newOffsets.triangleOffset;

            // Update lines.
            var lineWidth = itemStyleModel.get('borderWidth');
            var hasLine = lineWidth > 0;
            if (hasLine) {
                lineWidth *= api.getDevicePixelRatio();
                this._updateLinesGeometry(
                    linesMesh.geometry, componentModel, dataIndex, regionHeight, lineWidth,
                    componentModel.coordinateSystem.transform
                );
            }
            linesMesh.invisible = !hasLine;
            linesMesh.material.set({
                color: borderColorArr
            });
        }

        var polygonMesh = this._polygonMesh;
        polygonMesh.material.transparent = hasTranparentRegion;
        polygonMesh.material.depthMask = !hasTranparentRegion;
        polygonMesh.geometry.updateBoundingBox();

        polygonMesh.frontFace = this.extrudeY ? util_graphicGL.Mesh.CCW : util_graphicGL.Mesh.CW;

        // Update tangents
        if (polygonMesh.material.get('normalMap')) {
            polygonMesh.geometry.generateTangents();
        }

        polygonMesh.seriesIndex = componentModel.seriesIndex;

        polygonMesh.on('mousemove', this._onmousemove, this);
        polygonMesh.on('mouseout', this._onmouseout, this);
    },

    _updateDebugWireframe: function (componentModel) {
        var debugWireframeModel = componentModel.getModel('debug.wireframe');

        // TODO Unshow
        if (debugWireframeModel.get('show')) {
            var color = util_graphicGL.parseColor(
                debugWireframeModel.get('lineStyle.color') || 'rgba(0,0,0,0.5)'
            );
            var width = util_retrieve.firstNotNull(
                debugWireframeModel.get('lineStyle.width'), 1
            );

            // TODO  Will cause highlight wrong
            var mesh = this._polygonMesh;
            mesh.geometry.generateBarycentric();
            mesh.material.define('both', 'WIREFRAME_TRIANGLE');
            mesh.material.set('wireframeLineColor', color);
            mesh.material.set('wireframeLineWidth', width);
        }
    },

    _onmousemove: function (e) {
        var dataIndex = this._dataIndexOfVertex[e.triangle[0]];
        if (dataIndex == null) {
            dataIndex = -1;
        }
        if (dataIndex !== this._lastHoverDataIndex) {
            this.downplay(this._lastHoverDataIndex);
            this.highlight(dataIndex);
            this._labelsBuilder.updateLabels([dataIndex]);
        }
        this._lastHoverDataIndex = dataIndex;
        this._polygonMesh.dataIndex = dataIndex;
    },

    _onmouseout: function (e) {
        if (e.target) {
            this.downplay(this._lastHoverDataIndex);
            this._lastHoverDataIndex = -1;
            this._polygonMesh.dataIndex = -1;
        }

        this._labelsBuilder.updateLabels([]);
    },

    _updateGroundPlane: function (componentModel, geo3D, api) {
        var groundModel = componentModel.getModel('groundPlane', componentModel);
        this._groundMesh.invisible = !groundModel.get('show', true);
        if (this._groundMesh.invisible) {
            return;
        }

        var shading = componentModel.get('shading');
        var material = this._groundMaterials[shading];
        if (!material) {
            if (true) {
                console.warn('Unkown shading ' + shading);
            }
            material = this._groundMaterials.lambert;
        }

        util_graphicGL.setMaterialFromModel(shading, material, groundModel, api);
        if (material.get('normalMap')) {
            this._groundMesh.geometry.generateTangents();
        }

        this._groundMesh.material = material;
        this._groundMesh.material.set('color', util_graphicGL.parseColor(groundModel.get('color')));

        this._groundMesh.scale.set(geo3D.size[0], geo3D.size[2], 1);
    },

    _triangulation: function (componentModel, start, end) {
        this._triangulationResults = [];

        var minAll = [Infinity, Infinity, Infinity];
        var maxAll = [-Infinity, -Infinity, -Infinity];

        var coordSys = componentModel.coordinateSystem;

        for (var idx = start; idx < end; idx++) {
            var polygons = [];
            var polygonCoords = componentModel.getRegionPolygonCoords(idx);
            for (var i = 0; i < polygonCoords.length; i++) {
                var exterior = polygonCoords[i].exterior;
                var interiors = polygonCoords[i].interiors;
                var points = [];
                var holes = [];
                if (exterior.length < 3) {
                    continue;
                }
                var offset = 0;
                for (var j = 0; j < exterior.length; j++) {
                    var p = exterior[j];
                    points[offset++] = p[0];
                    points[offset++] = p[1];
                }

                for (var j = 0; j < interiors.length; j++) {
                    if (interiors[j].length < 3) {
                        continue;
                    }
                    var startIdx = points.length / 2;
                    for (var k = 0; k < interiors[j].length; k++) {
                        var p = interiors[j][k];
                        points.push(p[0]);
                        points.push(p[1]);
                    }

                    holes.push(startIdx);
                }
                var triangles = earcut(points, holes);

                var points3 = new Float64Array(points.length / 2 * 3);
                var pos = [];
                var min = [Infinity, Infinity, Infinity];
                var max = [-Infinity, -Infinity, -Infinity];
                var off3 = 0;
                for (var j = 0; j < points.length;) {
                    Geo3DBuilder_vec3.set(pos, points[j++], 0, points[j++]);
                    if (coordSys && coordSys.transform) {
                        Geo3DBuilder_vec3.transformMat4(pos, pos, coordSys.transform);
                    }
                    Geo3DBuilder_vec3.min(min, min, pos);
                    Geo3DBuilder_vec3.max(max, max, pos);
                    points3[off3++] = pos[0];
                    points3[off3++] = pos[1];
                    points3[off3++] = pos[2];
                }
                Geo3DBuilder_vec3.min(minAll, minAll, min);
                Geo3DBuilder_vec3.max(maxAll, maxAll, max);
                polygons.push({
                    points: points3,
                    indices: triangles,
                    min: min,
                    max: max
                });
            }
            this._triangulationResults.push(polygons);
        }

        this._geoBoundingBox = [minAll, maxAll];
    },

    /**
     * Get region vertex and triangle count
     */
    _getRegionPolygonInfo: function (idx) {

        var polygons = this._triangulationResults[idx - this._startIndex];

        var sideVertexCount = 0;
        var sideTriangleCount = 0;

        for (var i = 0; i < polygons.length; i++) {
            sideVertexCount += polygons[i].points.length / 3;
            sideTriangleCount += polygons[i].indices.length / 3;
        }

        var vertexCount = sideVertexCount * 2 + sideVertexCount * 4;
        var triangleCount = sideTriangleCount * 2 + sideVertexCount * 2;

        return {
            vertexCount: vertexCount,
            triangleCount: triangleCount
        };
    },

    _updatePolygonGeometry: function (
        componentModel, geometry, dataIndex, regionHeight,
        vertexOffset, triangleOffset, color
    ) {
        // FIXME
        var projectUVOnGround = componentModel.get('projectUVOnGround');

        var positionAttr = geometry.attributes.position;
        var normalAttr = geometry.attributes.normal;
        var texcoordAttr = geometry.attributes.texcoord0;
        var colorAttr = geometry.attributes.color;
        var polygons = this._triangulationResults[dataIndex - this._startIndex];

        var hasColor = colorAttr.value && color;

        var indices = geometry.indices;

        var extrudeCoordIndex = this.extrudeY ? 1 : 2;
        var sideCoordIndex = this.extrudeY ? 2 : 1;

        var scale = [
            this.rootNode.worldTransform.x.len(),
            this.rootNode.worldTransform.y.len(),
            this.rootNode.worldTransform.z.len()
        ];

        var min = Geo3DBuilder_vec3.mul([], this._geoBoundingBox[0], scale);
        var max = Geo3DBuilder_vec3.mul([], this._geoBoundingBox[1], scale);
        var maxDimSize = Math.max(max[0] - min[0], max[2] - min[2]);

        function addVertices(polygon, y, insideOffset) {
            var points = polygon.points;

            var pointsLen = points.length;
            var currentPosition = [];
            var uv = [];

            for (var k = 0; k < pointsLen; k += 3) {
                currentPosition[0] = points[k];
                currentPosition[extrudeCoordIndex] = y;
                currentPosition[sideCoordIndex] = points[k + 2];

                uv[0] = (points[k] * scale[0] - min[0]) / maxDimSize;
                uv[1] = (points[k + 2] * scale[sideCoordIndex] - min[2]) / maxDimSize;

                positionAttr.set(vertexOffset, currentPosition);
                if (hasColor) {
                    colorAttr.set(vertexOffset, color);
                }
                texcoordAttr.set(vertexOffset++, uv);
            }
        }

        function buildTopBottom(polygon, y, insideOffset) {

            var startVertexOffset = vertexOffset;

            addVertices(polygon, y, insideOffset);

            var len = polygon.indices.length;
            for (var k = 0; k < len; k++) {
                indices[triangleOffset * 3 + k] = polygon.indices[k] + startVertexOffset;
            }
            triangleOffset += polygon.indices.length / 3;
        }

        var normalTop = this.extrudeY ? [0, 1, 0] : [0, 0, 1];
        var normalBottom = Geo3DBuilder_vec3.negate([], normalTop);
        for (var p = 0; p < polygons.length; p++) {
            var startVertexOffset = vertexOffset;
            var polygon = polygons[p];
            // BOTTOM
            buildTopBottom(polygon, 0, 0);
            // TOP
            buildTopBottom(polygon, regionHeight, 0);

            var ringVertexCount = polygon.points.length / 3;
            for (var v = 0; v < ringVertexCount; v++) {
                normalAttr.set(startVertexOffset + v, normalBottom);
                normalAttr.set(startVertexOffset + v + ringVertexCount, normalTop);
            }

            var quadToTriangle = [0, 3, 1, 1, 3, 2];

            var quadPos = [[], [], [], []];
            var a = [];
            var b = [];
            var normal = [];
            var uv = [];
            var len = 0;
            for (var v = 0; v < ringVertexCount; v++) {
                var next = (v + 1) % ringVertexCount;

                var dx = (polygon.points[next * 3] - polygon.points[v * 3]) * scale[0];
                var dy = (polygon.points[next * 3 + 2] - polygon.points[v * 3 + 2]) * scale[sideCoordIndex];
                var sideLen = Math.sqrt(dx * dx + dy * dy);

                // 0----1
                // 3----2
                for (var k = 0; k < 4; k++) {
                    var isCurrent = (k === 0 || k === 3);
                    var idx3 = (isCurrent ? v : next) * 3;
                    quadPos[k][0] = polygon.points[idx3];
                    quadPos[k][extrudeCoordIndex] = k > 1 ? regionHeight : 0;
                    quadPos[k][sideCoordIndex] = polygon.points[idx3 + 2];

                    positionAttr.set(vertexOffset + k, quadPos[k]);

                    if (projectUVOnGround) {
                        uv[0] = (polygon.points[idx3] * scale[0] - min[0]) / maxDimSize;
                        uv[1] = (polygon.points[idx3 + 2] * scale[sideCoordIndex] - min[sideCoordIndex]) / maxDimSize;
                    }
                    else {
                        uv[0] = (isCurrent ? len : (len + sideLen)) / maxDimSize;
                        uv[1] = (quadPos[k][extrudeCoordIndex] * scale[extrudeCoordIndex] - min[extrudeCoordIndex])  / maxDimSize;
                    }
                    texcoordAttr.set(vertexOffset + k, uv);
                }
                Geo3DBuilder_vec3.sub(a, quadPos[1], quadPos[0]);
                Geo3DBuilder_vec3.sub(b, quadPos[3], quadPos[0]);
                Geo3DBuilder_vec3.cross(normal, a, b);
                Geo3DBuilder_vec3.normalize(normal, normal);

                for (var k = 0; k < 4; k++) {
                    normalAttr.set(vertexOffset + k, normal);
                    if (hasColor) {
                        colorAttr.set(vertexOffset + k, color);
                    }
                }

                for (var k = 0; k < 6; k++) {
                    indices[triangleOffset * 3 + k] = quadToTriangle[k] + vertexOffset;
                }

                vertexOffset += 4;
                triangleOffset += 2;

                len += sideLen;
            }
        }

        geometry.dirty();

        return {
            vertexOffset: vertexOffset,
            triangleOffset: triangleOffset
        };
    },

    _getRegionLinesInfo: function (idx, componentModel, geometry) {
        var vertexCount = 0;
        var triangleCount = 0;

        var regionModel = componentModel.getRegionModel(idx);
        var itemStyleModel = regionModel.getModel('itemStyle');

        var lineWidth = itemStyleModel.get('borderWidth');
        if (lineWidth > 0) {
            var polygonCoords = componentModel.getRegionPolygonCoords(idx);
            polygonCoords.forEach(function (coords) {
                var exterior = coords.exterior;
                var interiors = coords.interiors;
                vertexCount += geometry.getPolylineVertexCount(exterior);
                triangleCount += geometry.getPolylineTriangleCount(exterior);
                for (var i = 0; i < interiors.length; i++) {
                    vertexCount += geometry.getPolylineVertexCount(interiors[i]);
                    triangleCount += geometry.getPolylineTriangleCount(interiors[i]);
                }
            }, this);
        }

        return {
            vertexCount: vertexCount,
            triangleCount: triangleCount
        };

    },

    _updateLinesGeometry: function (geometry, componentModel, dataIndex, regionHeight, lineWidth, transform) {
        function convertToPoints3(polygon) {
            var points = new Float64Array(polygon.length * 3);
            var offset = 0;
            var pos = [];
            for (var i = 0; i < polygon.length; i++) {
                pos[0] = polygon[i][0];
                // Add a offset to avoid z-fighting
                pos[1] = regionHeight + 0.1;
                pos[2] = polygon[i][1];

                if (transform) {
                    Geo3DBuilder_vec3.transformMat4(pos, pos, transform);
                }

                points[offset++] = pos[0];
                points[offset++] = pos[1];
                points[offset++] = pos[2];
            }
            return points;
        }

        var whiteColor = [1, 1, 1, 1];
        var coords = componentModel.getRegionPolygonCoords(dataIndex);
        coords.forEach(function (geo) {
            var exterior = geo.exterior;
            var interiors = geo.interiors;

            geometry.addPolyline(convertToPoints3(exterior), whiteColor, lineWidth);

            for (var i = 0; i < interiors.length; i++) {
                geometry.addPolyline(convertToPoints3(interiors[i]), whiteColor, lineWidth);
            }
        });
    },

    highlight: function (dataIndex) {
        var data = this._data;
        if (!data) {
            return;
        }

        var itemModel = data.getItemModel(dataIndex);
        var emphasisItemStyleModel = itemModel.getModel(['emphasis', 'itemStyle']);
        var emphasisColor = emphasisItemStyleModel.get('color');
        var emphasisOpacity = util_retrieve.firstNotNull(
            emphasisItemStyleModel.get('opacity'),
            getItemVisualOpacity(data, dataIndex),
            1
        );
        if (emphasisColor == null) {
            var color = getItemVisualColor(data, dataIndex);
            emphasisColor = external_echarts_.color.lift(color, -0.4);
        }
        if (emphasisOpacity == null) {
            emphasisOpacity = getItemVisualOpacity(data, dataIndex);
        }
        var colorArr = util_graphicGL.parseColor(emphasisColor);
        colorArr[3] *= emphasisOpacity;

        this._setColorOfDataIndex(data, dataIndex, colorArr);
    },

    downplay: function (dataIndex) {

        var data = this._data;
        if (!data) {
            return;
        }

        var color = util_retrieve.firstNotNull(
            getItemVisualColor(data, dataIndex),
            data.getItemModel(dataIndex).get(['itemStyle', 'color']),
            '#fff'
        );
        var opacity = util_retrieve.firstNotNull(getItemVisualOpacity(data, dataIndex), 1);

        var colorArr = util_graphicGL.parseColor(color);
        colorArr[3] *= opacity;

        this._setColorOfDataIndex(data, dataIndex, colorArr);
    },

    dispose: function () {
        this._labelsBuilder.dispose();
    },

    _setColorOfDataIndex: function (data, dataIndex, colorArr) {
        if (dataIndex < this._startIndex && dataIndex > this._endIndex) {
            return;
        }
        dataIndex -= this._startIndex;
        for (var i = this._vertexRangeOfDataIndex[dataIndex * 2]; i < this._vertexRangeOfDataIndex[dataIndex * 2 + 1]; i++) {
            this._polygonMesh.geometry.attributes.color.set(i, colorArr);
        }
        this._polygonMesh.geometry.dirty();
        this._api.getZr().refresh();
    }
};

/* harmony default export */ const common_Geo3DBuilder = (Geo3DBuilder);
;// CONCATENATED MODULE: ./src/component/geo3D/Geo3DView.js







/* harmony default export */ const Geo3DView = (external_echarts_.ComponentView.extend({

    type: 'geo3D',

    __ecgl__: true,

    init: function (ecModel, api) {

        this._geo3DBuilder = new common_Geo3DBuilder(api);
        this.groupGL = new util_graphicGL.Node();

        this._lightRoot = new util_graphicGL.Node();
        this._sceneHelper = new common_SceneHelper(this._lightRoot);
        this._sceneHelper.initLight(this._lightRoot);

        this._control = new util_OrbitControl({
            zr: api.getZr()
        });
        this._control.init();
    },

    render: function (geo3DModel, ecModel, api) {
        this.groupGL.add(this._geo3DBuilder.rootNode);

        var geo3D = geo3DModel.coordinateSystem;

        if (!geo3D || !geo3D.viewGL) {
            return;
        }

        // Always have light.
        geo3D.viewGL.add(this._lightRoot);

        if (geo3DModel.get('show')) {
            geo3D.viewGL.add(this.groupGL);
        }
        else {
            geo3D.viewGL.remove(this.groupGL);
        }

        var control = this._control;
        control.setViewGL(geo3D.viewGL);

        var viewControlModel = geo3DModel.getModel('viewControl');
        control.setFromViewControlModel(viewControlModel, 0);

        this._sceneHelper.setScene(geo3D.viewGL.scene);
        this._sceneHelper.updateLight(geo3DModel);

        // Set post effect
        geo3D.viewGL.setPostEffect(geo3DModel.getModel('postEffect'), api);
        geo3D.viewGL.setTemporalSuperSampling(geo3DModel.getModel('temporalSuperSampling'));

        // Must update after geo3D.viewGL.setPostEffect
        this._geo3DBuilder.update(geo3DModel, ecModel, api, 0, geo3DModel.getData().count());
        var srgbDefineMethod = geo3D.viewGL.isLinearSpace() ? 'define' : 'undefine';
        this._geo3DBuilder.rootNode.traverse(function (mesh) {
            if (mesh.material) {
                mesh.material[srgbDefineMethod]('fragment', 'SRGB_DECODE');
            }
        });

        control.off('update');
        control.on('update', function () {
            api.dispatchAction({
                type: 'geo3DChangeCamera',
                alpha: control.getAlpha(),
                beta: control.getBeta(),
                distance: control.getDistance(),
                center: control.getCenter(),
                from: this.uid,
                geo3DId: geo3DModel.id
            });
        });
        control.update();
    },

    afterRender: function (geo3DModel, ecModel, api, layerGL) {
        var renderer = layerGL.renderer;
        this._sceneHelper.updateAmbientCubemap(renderer, geo3DModel, api);

        this._sceneHelper.updateSkybox(renderer, geo3DModel, api);
    },

    dispose: function () {
        this._control.dispose();
        this._geo3DBuilder.dispose();
    }
}));
;// CONCATENATED MODULE: ./node_modules/echarts/lib/coord/geo/fix/textCoord.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var coordsOffsetMap = {
  '南海诸岛': [32, 80],
  // 全国
  '广东': [0, -10],
  '香港': [10, 5],
  '澳门': [-10, 10],
  //'北京': [-10, 0],
  '天津': [5, 5]
};
function fixTextCoords(mapType, region) {
  if (mapType === 'china') {
    var coordFix = coordsOffsetMap[region.name];

    if (coordFix) {
      var cp = region.getCenter();
      cp[0] += coordFix[0] / 10.5;
      cp[1] += -coordFix[1] / (10.5 / 0.75);
      region.setCenter(cp);
    }
  }
}
;// CONCATENATED MODULE: ./node_modules/echarts/lib/coord/geo/fix/geoCoord.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var geoCoordMap = {
  'Russia': [100, 60],
  'United States': [-99, 38],
  'United States of America': [-99, 38]
};
function fixGeoCoords(mapType, region) {
  if (mapType === 'world') {
    var geoCoord = geoCoordMap[region.name];

    if (geoCoord) {
      var cp = [geoCoord[0], geoCoord[1]];
      region.setCenter(cp);
    }
  }
}
;// CONCATENATED MODULE: ./src/coord/geo3D/Geo3D.js


var Geo3D_vec3 = dep_glmatrix.vec3;
var Geo3D_mat4 = dep_glmatrix.mat4;



// Geo fix functions
var geoFixFuncs = [fixTextCoords, fixGeoCoords];

function Geo3D(name, map, geoJson, specialAreas, nameMap) {

    this.name = name;

    this.map = map;

    this.regionHeight = 0;

    this.regions = [];

    this._nameCoordMap = {};

    this.loadGeoJson(geoJson, specialAreas, nameMap);

    this.transform = Geo3D_mat4.identity(new Float64Array(16));

    this.invTransform = Geo3D_mat4.identity(new Float64Array(16));

    // Which dimension to extrude. Y or Z
    this.extrudeY = true;

    this.altitudeAxis;
}

Geo3D.prototype = {

    constructor: Geo3D,

    type: 'geo3D',

    dimensions: ['lng', 'lat', 'alt'],

    containPoint: function () {},

    loadGeoJson: function (geoJson, specialAreas, nameMap) {
        var parseGeoJSON = external_echarts_.parseGeoJSON || external_echarts_.parseGeoJson;
        try {
            this.regions = geoJson ? parseGeoJSON(geoJson) : [];
        }
        catch (e) {
            throw 'Invalid geoJson format\n' + e;
        }
        specialAreas = specialAreas || {};
        nameMap = nameMap || {};
        var regions = this.regions;
        var regionsMap = {};
        for (var i = 0; i < regions.length; i++) {
            var regionName = regions[i].name;
            // Try use the alias in nameMap
            regionName = nameMap[regionName] || regionName;
            regions[i].name = regionName;

            regionsMap[regionName] = regions[i];
            // Add geoJson
            this.addGeoCoord(regionName, regions[i].getCenter());

            // Some area like Alaska in USA map needs to be tansformed
            // to look better
            var specialArea = specialAreas[regionName];
            if (specialArea) {
                regions[i].transformTo(
                    specialArea.left, specialArea.top, specialArea.width, specialArea.height
                );
            }
        }

        this._regionsMap = regionsMap;

        this._geoRect = null;

        geoFixFuncs.forEach(function (fixFunc) {
            fixFunc(this);
        }, this);
    },

    getGeoBoundingRect: function () {
        if (this._geoRect) {
            return this._geoRect;
        }
        var rect;

        var regions = this.regions;
        for (var i = 0; i < regions.length; i++) {
            var regionRect = regions[i].getBoundingRect();
            rect = rect || regionRect.clone();
            rect.union(regionRect);
        }
        // FIXME Always return new ?
        return (this._geoRect = rect || new external_echarts_.graphic.BoundingRect(0, 0, 0, 0));
    },

    /**
     * Add geoCoord for indexing by name
     * @param {string} name
     * @param {Array.<number>} geoCoord
     */
    addGeoCoord: function (name, geoCoord) {
        this._nameCoordMap[name] = geoCoord;
    },

    /**
     * @param {string} name
     * @return {module:echarts/coord/geo/Region}
     */
    getRegion: function (name) {
        return this._regionsMap[name];
    },

    getRegionByCoord: function (coord) {
        var regions = this.regions;
        for (var i = 0; i < regions.length; i++) {
            if (regions[i].contain(coord)) {
                return regions[i];
            }
        }
    },

    setSize: function (width, height, depth) {
        this.size = [width, height, depth];

        var rect = this.getGeoBoundingRect();

        var scaleX = width / rect.width;
        var scaleZ = -depth / rect.height;
        var translateX = -width / 2 - rect.x * scaleX;
        var translateZ = depth / 2 - rect.y * scaleZ;

        var position = this.extrudeY ? [translateX, 0, translateZ] : [translateX, translateZ, 0];
        var scale = this.extrudeY ? [scaleX, 1, scaleZ] : [scaleX, scaleZ, 1];

        var m = this.transform;
        Geo3D_mat4.identity(m);
        Geo3D_mat4.translate(m, m, position);
        Geo3D_mat4.scale(m, m, scale);

        Geo3D_mat4.invert(this.invTransform, m);
    },

    dataToPoint: function (data, out) {
        out = out || [];

        var extrudeCoordIndex = this.extrudeY ? 1 : 2;
        var sideCoordIndex = this.extrudeY ? 2 : 1;

        var altitudeVal = data[2];
        // PENDING.
        if (isNaN(altitudeVal)) {
            altitudeVal = 0;
        }
        // lng
        out[0] = data[0];
        // lat
        out[sideCoordIndex] = data[1];

        if (this.altitudeAxis) {
            out[extrudeCoordIndex] = this.altitudeAxis.dataToCoord(altitudeVal);
        }
        else {
            out[extrudeCoordIndex] = 0;
        }
        // PENDING different region height.
        out[extrudeCoordIndex] += this.regionHeight;

        Geo3D_vec3.transformMat4(out, out, this.transform);

        return out;
    },

    pointToData: function (point, out) {
        // TODO
    }
};

/* harmony default export */ const geo3D_Geo3D = (Geo3D);
;// CONCATENATED MODULE: ./src/coord/geo3DCreator.js






function resizeGeo3D(geo3DModel, api) {
    // Use left/top/width/height
    var boxLayoutOption = geo3DModel.getBoxLayoutParams();

    var viewport = getLayoutRect(boxLayoutOption, {
        width: api.getWidth(),
        height: api.getHeight()
    });

    // Flip Y
    viewport.y = api.getHeight() - viewport.y - viewport.height;

    this.viewGL.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, api.getDevicePixelRatio());

    var geoRect = this.getGeoBoundingRect();
    var aspect = geoRect.width / geoRect.height * (geo3DModel.get('aspectScale') || 0.75);

    var width = geo3DModel.get('boxWidth');
    var depth = geo3DModel.get('boxDepth');
    var height = geo3DModel.get('boxHeight');
    if (height == null) {
        height = 5;
    }
    if (isNaN(width) && isNaN(depth)) {
        // Default to have 100 width
        width = 100;
    }
    if (isNaN(depth)) {
        depth = width / aspect;
    }
    else if (isNaN(width)) {
        width = depth / aspect;
    }

    this.setSize(width, height, depth);

    this.regionHeight = geo3DModel.get('regionHeight');

    if (this.altitudeAxis) {
        this.altitudeAxis.setExtent(0, Math.max(height - this.regionHeight, 0));
    }
}

function updateGeo3D(ecModel, api) {

    var altitudeDataExtent = [Infinity, -Infinity];

    ecModel.eachSeries(function (seriesModel) {
        if (seriesModel.coordinateSystem !== this) {
            return;
        }
        if (seriesModel.type === 'series.map3D') {
            return;
        }
        // Get altitude data extent.
        var data = seriesModel.getData();
        var altDims = seriesModel.coordDimToDataDim('alt');
        var altDim = altDims && altDims[0];
        if (altDim) {
            // TODO altitiude is in coords of lines.
            var dataExtent = data.getDataExtent(altDim, true);
            altitudeDataExtent[0] = Math.min(
                altitudeDataExtent[0], dataExtent[0]
            );
            altitudeDataExtent[1] = Math.max(
                altitudeDataExtent[1], dataExtent[1]
            );
        }
    }, this);
    // Create altitude axis
    if (altitudeDataExtent && isFinite(altitudeDataExtent[1] - altitudeDataExtent[0])) {
        var scale = external_echarts_.helper.createScale(
            altitudeDataExtent, {
                type: 'value',
                // PENDING
                min: 'dataMin',
                max: 'dataMax'
            }
        );
        this.altitudeAxis = new external_echarts_.Axis('altitude', scale);
        // Resize again
        this.resize(this.model, api);
    }
}


if (true) {
    var mapNotExistsError = function (name) {
        console.error('Map ' + name + ' not exists. You can download map file on http://echarts.baidu.com/download-map.html');
    };
}


var geo3DCreator_idStart = 0;

var geo3DCreator = {

    dimensions: geo3D_Geo3D.prototype.dimensions,

    create: function (ecModel, api) {

        var geo3DList = [];

        if (!external_echarts_.getMap) {
            throw new Error('geo3D component depends on geo component');
        }

        function createGeo3D(componentModel, idx) {

            var geo3D = geo3DCreator.createGeo3D(componentModel);

            // FIXME
            componentModel.__viewGL = componentModel.__viewGL || new core_ViewGL();

            geo3D.viewGL = componentModel.__viewGL;

            componentModel.coordinateSystem = geo3D;
            geo3D.model = componentModel;

            geo3DList.push(geo3D);

            // Inject resize
            geo3D.resize = resizeGeo3D;
            geo3D.resize(componentModel, api);

            geo3D.update = updateGeo3D;
        }

        ecModel.eachComponent('geo3D', function (geo3DModel, idx) {
            createGeo3D(geo3DModel, idx);
        });

        ecModel.eachSeriesByType('map3D', function (map3DModel, idx) {
            var coordSys = map3DModel.get('coordinateSystem');
            if (coordSys == null) {
                coordSys = 'geo3D';
            }
            if (coordSys === 'geo3D') {
                createGeo3D(map3DModel, idx);
            }
        });

        ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.get('coordinateSystem') === 'geo3D') {
                if (seriesModel.type === 'series.map3D') {
                    return;
                }
                var geo3DModel = seriesModel.getReferringComponents('geo3D').models[0];
                if (!geo3DModel) {
                    geo3DModel = ecModel.getComponent('geo3D');
                }

                if (!geo3DModel) {
                    throw new Error('geo "' + util_retrieve.firstNotNull(
                        seriesModel.get('geo3DIndex'),
                        seriesModel.get('geo3DId'),
                        0
                    ) + '" not found');
                }

                seriesModel.coordinateSystem = geo3DModel.coordinateSystem;
            }
        });

        return geo3DList;
    },

    createGeo3D: function (componentModel) {

        var mapData = componentModel.get('map');
        var name;
        if (typeof mapData === 'string') {
            name = mapData;
            mapData = external_echarts_.getMap(mapData);
        }
        else {
            if (mapData && mapData.features) {
                mapData = {
                    geoJson: mapData
                };
            }
        }
        if (true) {
            if (!mapData) {
                mapNotExistsError(mapData);
            }
            if (!mapData.geoJson.features) {
                throw new Error('Invalid GeoJSON for map3D');
            }
        }
        if (name == null) {
            name = 'GEO_ANONYMOUS_' + geo3DCreator_idStart++;
        }

        return new geo3D_Geo3D(
            name + geo3DCreator_idStart++, name,
            mapData && mapData.geoJson, mapData && mapData.specialAreas,
            componentModel.get('nameMap')
        );
    }
};

/* harmony default export */ const coord_geo3DCreator = (geo3DCreator);
;// CONCATENATED MODULE: ./src/component/geo3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.






function install_install(registers) {
    registers.registerComponentModel(geo3D_Geo3DModel);
    registers.registerComponentView(Geo3DView);

    registers.registerAction({
        type: 'geo3DChangeCamera',
        event: 'geo3dcamerachanged',
        update: 'series:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'geo3D', query: payload
        }, function (componentModel) {
            componentModel.setView(payload);
        });
    });

    registers.registerCoordinateSystem('geo3D', coord_geo3DCreator);

}
;// CONCATENATED MODULE: ./src/component/geo3D.js


(0,external_echarts_.use)(install_install);
;// CONCATENATED MODULE: ./src/component/globe/GlobeModel.js







function defaultId(option, idx) {
    option.id = option.id || option.name || (idx + '');
}
var GlobeModel = external_echarts_.ComponentModel.extend({

    type: 'globe',

    layoutMode: 'box',

    coordinateSystem: null,

    init: function () {
        GlobeModel.superApply(this, 'init', arguments);

        external_echarts_.util.each(this.option.layers, function (layerOption, idx) {
            external_echarts_.util.merge(layerOption, this.defaultLayerOption);
            defaultId(layerOption, idx);
        }, this);
    },

    mergeOption: function (option) {
        // TODO test
        var oldLayers = this.option.layers;
        this.option.layers = null;
        GlobeModel.superApply(this, 'mergeOption', arguments);

        function createLayerMap(layers) {
            return external_echarts_.util.reduce(layers, function (obj, layerOption, idx) {
                defaultId(layerOption, idx);
                obj[layerOption.id] = layerOption;
                return obj;
            }, {});
        }
        if (oldLayers && oldLayers.length) {
            var newLayerMap = createLayerMap(option.layers);
            var oldLayerMap = createLayerMap(oldLayers);
            for (var id in newLayerMap) {
                if (oldLayerMap[id]) {
                    external_echarts_.util.merge(oldLayerMap[id], newLayerMap[id], true);
                }
                else {
                    oldLayers.push(option.layers[id]);
                }
            }
            // Copy back
            this.option.layers = oldLayers;
        }
        // else overwrite

        // Set default
        external_echarts_.util.each(this.option.layers, function (layerOption) {
            external_echarts_.util.merge(layerOption, this.defaultLayerOption);
        }, this);
    },

    optionUpdated: function () {
        this.updateDisplacementHash();
    },

    defaultLayerOption: {
        show: true,
        type: 'overlay'
    },

    defaultOption: {

        show: true,

        zlevel: -10,

        // Layout used for viewport
        left: 0,
        top: 0,
        width: '100%',
        height: '100%',

        environment: 'auto',

        baseColor: '#fff',

        // Base albedo texture
        baseTexture: '',

        // Height texture for bump mapping and vertex displacement
        heightTexture: '',

        // Texture for vertex displacement, default use heightTexture
        displacementTexture: '',
        // Scale of vertex displacement, available only if displacementTexture is set.
        displacementScale: 0,

        // Detail of displacement. 'low', 'medium', 'high', 'ultra'
        displacementQuality: 'medium',

        // Globe radius
        globeRadius: 100,

        // Globe outer radius. Which is max of altitude.
        globeOuterRadius: 150,

        // Shading of globe
        shading: 'lambert',

        // Extend light
        light: {
            // Main sun light
            main: {
                // Time, default it will use system time
                time: ''
            }
        },

        // atmosphere
        atmosphere: {
            show: false,
            offset: 5,
            color: '#ffffff',
            glowPower: 6.0,
            innerGlowPower: 2.0
        },

        // light
        // postEffect
        // temporalSuperSampling

        viewControl: {
            autoRotate: true,

            panSensitivity: 0,

            targetCoord: null
        },


        // {
        //     show: true,
        //     name: 'cloud',
        //     type: 'overlay',
        //     shading: 'lambert',
        //     distance: 10,
        //     texture: ''
        // }
        // {
        //     type: 'blend',
        //     blendTo: 'albedo'
        //     blendType: 'source-over'
        // }

        layers: []
    },

    setDisplacementData: function (data, width, height) {
        this.displacementData = data;
        this.displacementWidth = width;
        this.displacementHeight = height;
    },

    getDisplacementTexture: function () {
        return this.get('displacementTexture') || this.get('heightTexture');
    },

    getDisplacemenScale: function () {
        var displacementTexture = this.getDisplacementTexture();
        var displacementScale = this.get('displacementScale');
        if (!displacementTexture || displacementTexture === 'none') {
            displacementScale = 0;
        }
        return displacementScale;
    },

    hasDisplacement: function () {
        return this.getDisplacemenScale() > 0;
    },

    _displacementChanged: true,

    _displacementScale: 0,

    updateDisplacementHash: function () {
        var displacementTexture = this.getDisplacementTexture();
        var displacementScale = this.getDisplacemenScale();

        this._displacementChanged =
            this._displacementTexture !== displacementTexture
            || this._displacementScale !== displacementScale;

        this._displacementTexture = displacementTexture;
        this._displacementScale = displacementScale;
    },

    isDisplacementChanged: function () {
        return this._displacementChanged;
    }
});

external_echarts_.util.merge(GlobeModel.prototype, componentViewControlMixin);
external_echarts_.util.merge(GlobeModel.prototype, componentPostEffectMixin);
external_echarts_.util.merge(GlobeModel.prototype, componentLightMixin);
external_echarts_.util.merge(GlobeModel.prototype, componentShadingMixin);

/* harmony default export */ const globe_GlobeModel = (GlobeModel);
;// CONCATENATED MODULE: ./src/util/sunCalc.js
/*
 (c) 2011-2014, Vladimir Agafonkin
 SunCalc is a JavaScript library for calculating sun/mooon position and light phases.
 https://github.com/mourner/suncalc
*/

// shortcuts for easier to read formulas

var sunCalc_PI   = Math.PI,
    sin  = Math.sin,
    cos  = Math.cos,
    tan  = Math.tan,
    sunCalc_asin = Math.asin,
    atan = Math.atan2,
    rad  = sunCalc_PI / 180;

// sun calculations are based on http://aa.quae.nl/en/reken/zonpositie.html formulas


// date/time constants and conversions

var dayMs = 1000 * 60 * 60 * 24,
    J1970 = 2440588,
    J2000 = 2451545;

function toJulian (date) { return date.valueOf() / dayMs - 0.5 + J1970; }
function toDays (date)   { return toJulian(date) - J2000; }


// general calculations for position

var sunCalc_e = rad * 23.4397; // obliquity of the Earth

function rightAscension(l, b) { return atan(sin(l) * cos(sunCalc_e) - tan(b) * sin(sunCalc_e), cos(l)); }
function declination(l, b)    { return sunCalc_asin(sin(b) * cos(sunCalc_e) + cos(b) * sin(sunCalc_e) * sin(l)); }

function azimuth(H, phi, dec)  { return atan(sin(H), cos(H) * sin(phi) - tan(dec) * cos(phi)); }
function altitude(H, phi, dec) { return sunCalc_asin(sin(phi) * sin(dec) + cos(phi) * cos(dec) * cos(H)); }

function siderealTime(d, lw) { return rad * (280.16 + 360.9856235 * d) - lw; }


// general sun calculations

function solarMeanAnomaly(d) { return rad * (357.5291 + 0.98560028 * d); }

function eclipticLongitude(M) {

    var C = rad * (1.9148 * sin(M) + 0.02 * sin(2 * M) + 0.0003 * sin(3 * M)), // equation of center
        P = rad * 102.9372; // perihelion of the Earth

    return M + C + P + sunCalc_PI;
}

function sunCoords(d) {

    var M = solarMeanAnomaly(d),
        L = eclipticLongitude(M);

    return {
        dec: declination(L, 0),
        ra: rightAscension(L, 0)
    };
}

var SunCalc = {};

// calculates sun position for a given date and latitude/longitude

SunCalc.getPosition = function (date, lat, lng) {

    var lw  = rad * -lng,
        phi = rad * lat,
        d   = toDays(date),

        c  = sunCoords(d),
        H  = siderealTime(d, lw) - c.ra;

    return {
        azimuth: azimuth(H, phi, c.dec),
        altitude: altitude(H, phi, c.dec)
    };
};

/* harmony default export */ const sunCalc = (SunCalc);
;// CONCATENATED MODULE: ./src/component/globe/atmosphere.glsl.js
/* harmony default export */ const atmosphere_glsl = ("@export ecgl.atmosphere.vertex\nattribute vec3 position: POSITION;\nattribute vec3 normal : NORMAL;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 normalMatrix : WORLDINVERSETRANSPOSE;\n\nvarying vec3 v_Normal;\n\nvoid main() {\n v_Normal = normalize((normalMatrix * vec4(normal, 0.0)).xyz);\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n\n\n@export ecgl.atmosphere.fragment\nuniform mat4 viewTranspose: VIEWTRANSPOSE;\nuniform float glowPower;\nuniform vec3 glowColor;\n\nvarying vec3 v_Normal;\n\nvoid main() {\n float intensity = pow(1.0 - dot(v_Normal, (viewTranspose * vec4(0.0, 0.0, 1.0, 0.0)).xyz), glowPower);\n gl_FragColor = vec4(glowColor, intensity * intensity);\n}\n@end");

;// CONCATENATED MODULE: ./src/component/globe/GlobeView.js












util_graphicGL.Shader.import(util_glsl);
util_graphicGL.Shader.import(atmosphere_glsl);

/* harmony default export */ const GlobeView = (external_echarts_.ComponentView.extend({

    type: 'globe',

    __ecgl__: true,

    _displacementScale: 0,

    init: function (ecModel, api) {
        this.groupGL = new util_graphicGL.Node();

        /**
         * @type {clay.geometry.Sphere}
         * @private
         */
        this._sphereGeometry = new util_graphicGL.SphereGeometry({
            widthSegments: 200,
            heightSegments: 100,
            dynamic: true
        });
        this._overlayGeometry = new util_graphicGL.SphereGeometry({
            widthSegments: 80,
            heightSegments: 40
        });

        /**
         * @type {clay.geometry.Plane}
         */
        this._planeGeometry = new util_graphicGL.PlaneGeometry();

        /**
         * @type {clay.geometry.Mesh}
         */
        this._earthMesh = new util_graphicGL.Mesh({
            renderNormal: true
        });

        /**
         * @type {clay.geometry.Mesh}
         */
        this._atmosphereMesh = new util_graphicGL.Mesh();
        this._atmosphereGeometry = new util_graphicGL.SphereGeometry({
            widthSegments: 80,
            heightSegments: 40
        });
        this._atmosphereMaterial = new util_graphicGL.Material({
            shader: new util_graphicGL.Shader(
                util_graphicGL.Shader.source('ecgl.atmosphere.vertex'),
                util_graphicGL.Shader.source('ecgl.atmosphere.fragment')
            ),
            transparent: true
        });
        this._atmosphereMesh.geometry = this._atmosphereGeometry;
        this._atmosphereMesh.material = this._atmosphereMaterial;
        this._atmosphereMesh.frontFace = util_graphicGL.Mesh.CW;

        this._lightRoot = new util_graphicGL.Node();
        this._sceneHelper = new common_SceneHelper();
        this._sceneHelper.initLight(this._lightRoot);

        this.groupGL.add(this._atmosphereMesh);
        this.groupGL.add(this._earthMesh);

        this._control = new util_OrbitControl({
            zr: api.getZr()
        });

        this._control.init();

        this._layerMeshes = {};
    },

    render: function (globeModel, ecModel, api) {
        var coordSys = globeModel.coordinateSystem;
        var shading = globeModel.get('shading');

        // Always have light.
        coordSys.viewGL.add(this._lightRoot);

        if (globeModel.get('show')) {
            // Add self to scene;
            coordSys.viewGL.add(this.groupGL);
        }
        else {
            coordSys.viewGL.remove(this.groupGL);
        }

        this._sceneHelper.setScene(coordSys.viewGL.scene);

        // Set post effect
        coordSys.viewGL.setPostEffect(globeModel.getModel('postEffect'), api);
        coordSys.viewGL.setTemporalSuperSampling(globeModel.getModel('temporalSuperSampling'));

        var earthMesh = this._earthMesh;

        earthMesh.geometry = this._sphereGeometry;

        var shadingPrefix = 'ecgl.' + shading;
        if (!earthMesh.material || earthMesh.material.shader.name !== shadingPrefix) {
            earthMesh.material = util_graphicGL.createMaterial(shadingPrefix);
        }

        util_graphicGL.setMaterialFromModel(
            shading, earthMesh.material, globeModel, api
        );
        ['roughnessMap', 'metalnessMap', 'detailMap', 'normalMap'].forEach(function (texName) {
            var texture = earthMesh.material.get(texName);
            if (texture) {
                texture.flipY = false;
            }
        });

        earthMesh.material.set('color', util_graphicGL.parseColor(
            globeModel.get('baseColor')
        ));

        // shrink a little
        var scale = coordSys.radius * 0.99;
        earthMesh.scale.set(scale, scale, scale);

        if (globeModel.get('atmosphere.show')) {
            earthMesh.material.define('both', 'ATMOSPHERE_ENABLED');
            this._atmosphereMesh.invisible = false;
            this._atmosphereMaterial.setUniforms({
                glowPower: globeModel.get('atmosphere.glowPower') || 6.0,
                glowColor: globeModel.get('atmosphere.color') || '#ffffff'
            });
            earthMesh.material.setUniforms({
                glowPower: globeModel.get('atmosphere.innerGlowPower') || 2.0,
                glowColor: globeModel.get('atmosphere.color') || '#ffffff'
            });
            var offset = globeModel.get('atmosphere.offset') || 5;
            this._atmosphereMesh.scale.set(scale + offset, scale + offset, scale + offset);
        }
        else {
            earthMesh.material.undefine('both', 'ATMOSPHERE_ENABLED');
            this._atmosphereMesh.invisible = true;
        }

        var diffuseTexture = earthMesh.material.setTextureImage('diffuseMap', globeModel.get('baseTexture'), api, {
            flipY: false,
            anisotropic: 8
        });
        if (diffuseTexture && diffuseTexture.surface) {
            diffuseTexture.surface.attachToMesh(earthMesh);
        }

        // Update bump map
        var bumpTexture = earthMesh.material.setTextureImage('bumpMap', globeModel.get('heightTexture'), api, {
            flipY: false,
            anisotropic: 8
        });
        if (bumpTexture && bumpTexture.surface) {
            bumpTexture.surface.attachToMesh(earthMesh);
        }

        earthMesh.material[globeModel.get('postEffect.enable') ? 'define' : 'undefine']('fragment', 'SRGB_DECODE');

        this._updateLight(globeModel, api);

        this._displaceVertices(globeModel, api);

        this._updateViewControl(globeModel, api);

        this._updateLayers(globeModel, api);
    },

    afterRender: function (globeModel, ecModel, api, layerGL) {
        // Create ambient cubemap after render because we need to know the renderer.
        // TODO
        var renderer = layerGL.renderer;

        this._sceneHelper.updateAmbientCubemap(renderer, globeModel, api);

        this._sceneHelper.updateSkybox(renderer, globeModel, api);
    },


    _updateLayers: function (globeModel, api) {
        var coordSys = globeModel.coordinateSystem;
        var layers = globeModel.get('layers');

        var lastDistance = coordSys.radius;
        var layerDiffuseTextures = [];
        var layerDiffuseIntensity = [];

        var layerEmissiveTextures = [];
        var layerEmissionIntensity = [];
        external_echarts_.util.each(layers, function (layerOption) {
            var layerModel = new external_echarts_.Model(layerOption);
            var layerType = layerModel.get('type');

            var texture = util_graphicGL.loadTexture(layerModel.get('texture'), api, {
                flipY: false,
                anisotropic: 8
            });
            if (texture.surface) {
                texture.surface.attachToMesh(this._earthMesh);
            }

            if (layerType === 'blend') {
                var blendTo = layerModel.get('blendTo');
                var intensity = util_retrieve.firstNotNull(layerModel.get('intensity'), 1.0);
                if (blendTo === 'emission') {
                    layerEmissiveTextures.push(texture);
                    layerEmissionIntensity.push(intensity);
                }
                else { // Default is albedo
                    layerDiffuseTextures.push(texture);
                    layerDiffuseIntensity.push(intensity);
                }
            }
            else { // Default use overlay
                var id = layerModel.get('id');
                var overlayMesh = this._layerMeshes[id];
                if (!overlayMesh) {
                    overlayMesh = this._layerMeshes[id] = new util_graphicGL.Mesh({
                        geometry: this._overlayGeometry,
                        castShadow: false,
                        ignorePicking: true
                    });
                }
                var shading = layerModel.get('shading');

                if (shading === 'lambert') {
                    overlayMesh.material = overlayMesh.__lambertMaterial || new util_graphicGL.Material({
                        autoUpdateTextureStatus: false,
                        shader: util_graphicGL.createShader('ecgl.lambert'),
                        transparent: true,
                        depthMask: false
                    });
                    overlayMesh.__lambertMaterial = overlayMesh.material;
                }
                else { // color
                    overlayMesh.material = overlayMesh.__colorMaterial || new util_graphicGL.Material({
                        autoUpdateTextureStatus: false,
                        shader: util_graphicGL.createShader('ecgl.color'),
                        transparent: true,
                        depthMask: false
                    });
                    overlayMesh.__colorMaterial = overlayMesh.material;
                }
                // overlay should be transparent if texture is not loaded yet.
                overlayMesh.material.enableTexture('diffuseMap');

                var distance = layerModel.get('distance');
                // Based on distance of last layer
                var radius = lastDistance + (distance == null ? coordSys.radius / 100 : distance);
                overlayMesh.scale.set(radius, radius, radius);

                lastDistance = radius;

                // FIXME Exists blink.
                var blankTexture = this._blankTexture || (this._blankTexture = util_graphicGL.createBlankTexture('rgba(255, 255, 255, 0)'));
                overlayMesh.material.set('diffuseMap', blankTexture);

                util_graphicGL.loadTexture(layerModel.get('texture'), api, {
                    flipY: false,
                    anisotropic: 8
                }, function (texture) {
                    if (texture.surface) {
                        texture.surface.attachToMesh(overlayMesh);
                    }
                    overlayMesh.material.set('diffuseMap', texture);
                    api.getZr().refresh();
                });

                layerModel.get('show') ? this.groupGL.add(overlayMesh) : this.groupGL.remove(overlayMesh);
            }
        }, this);

        var earthMaterial = this._earthMesh.material;
        earthMaterial.define('fragment', 'LAYER_DIFFUSEMAP_COUNT', layerDiffuseTextures.length);
        earthMaterial.define('fragment', 'LAYER_EMISSIVEMAP_COUNT', layerEmissiveTextures.length);

        earthMaterial.set('layerDiffuseMap', layerDiffuseTextures);
        earthMaterial.set('layerDiffuseIntensity', layerDiffuseIntensity);
        earthMaterial.set('layerEmissiveMap', layerEmissiveTextures);
        earthMaterial.set('layerEmissionIntensity', layerEmissionIntensity);

        var debugWireframeModel = globeModel.getModel('debug.wireframe');
        if (debugWireframeModel.get('show')) {
            earthMaterial.define('both', 'WIREFRAME_TRIANGLE');
            var color = util_graphicGL.parseColor(
                debugWireframeModel.get('lineStyle.color') || 'rgba(0,0,0,0.5)'
            );
            var width = util_retrieve.firstNotNull(
                debugWireframeModel.get('lineStyle.width'), 1
            );
            earthMaterial.set('wireframeLineWidth', width);
            earthMaterial.set('wireframeLineColor', color);
        }
        else {
            earthMaterial.undefine('both', 'WIREFRAME_TRIANGLE');
        }
    },

    _updateViewControl: function (globeModel, api) {
        var coordSys = globeModel.coordinateSystem;
        // Update camera
        var viewControlModel = globeModel.getModel('viewControl');

        var camera = coordSys.viewGL.camera;
        var self = this;

        function makeAction() {
            return {
                type: 'globeChangeCamera',
                alpha: control.getAlpha(),
                beta: control.getBeta(),
                distance: control.getDistance() - coordSys.radius,
                center: control.getCenter(),
                from: self.uid,
                globeId: globeModel.id
            };
        }

        // Update control
        var control = this._control;
        control.setViewGL(coordSys.viewGL);

        var coord = viewControlModel.get('targetCoord');
        var alpha, beta;
        if (coord != null) {
            beta = coord[0] + 90;
            alpha = coord[1];
        }

        control.setFromViewControlModel(viewControlModel, {
            baseDistance: coordSys.radius,
            alpha: alpha,
            beta: beta
        });

        control.off('update');
        control.on('update', function () {
            api.dispatchAction(makeAction());
        });
    },

    _displaceVertices: function (globeModel, api) {
        var displacementQuality = globeModel.get('displacementQuality');
        var showDebugWireframe = globeModel.get('debug.wireframe.show');
        var globe = globeModel.coordinateSystem;

        if (!globeModel.isDisplacementChanged()
            && displacementQuality === this._displacementQuality
            && showDebugWireframe === this._showDebugWireframe
        ) {
            return;
        }

        this._displacementQuality = displacementQuality;
        this._showDebugWireframe = showDebugWireframe;

        var geometry = this._sphereGeometry;

        var widthSegments = ({
            low: 100,
            medium: 200,
            high: 400,
            ultra: 800
        })[displacementQuality] || 200;
        var heightSegments = widthSegments / 2;
        if (geometry.widthSegments !== widthSegments || showDebugWireframe) {
            geometry.widthSegments = widthSegments;
            geometry.heightSegments = heightSegments;
            geometry.build();
        }

        this._doDisplaceVertices(geometry, globe);

        if (showDebugWireframe) {
            geometry.generateBarycentric();
        }
    },

    _doDisplaceVertices: function (geometry, globe) {
        var positionArr = geometry.attributes.position.value;
        var uvArr = geometry.attributes.texcoord0.value;

        var originalPositionArr = geometry.__originalPosition;
        if (!originalPositionArr || originalPositionArr.length !== positionArr.length) {
            originalPositionArr = new Float32Array(positionArr.length);
            originalPositionArr.set(positionArr);
            geometry.__originalPosition = originalPositionArr;
        }

        var width = globe.displacementWidth;
        var height = globe.displacementHeight;
        var data = globe.displacementData;

        for (var i = 0; i < geometry.vertexCount; i++) {
            var i3 = i * 3;
            var i2 = i * 2;
            var x = originalPositionArr[i3 + 1];
            var y = originalPositionArr[i3 + 2];
            var z = originalPositionArr[i3 + 3];

            var u = uvArr[i2++];
            var v = uvArr[i2++];

            var j = Math.round(u * (width - 1));
            var k = Math.round(v * (height - 1));
            var idx = k * width + j;
            var scale = data ? data[idx] : 0;

            positionArr[i3 + 1] = x + x * scale;
            positionArr[i3 + 2] = y + y * scale;
            positionArr[i3 + 3] = z + z * scale;
        }

        geometry.generateVertexNormals();
        geometry.dirty();

        geometry.updateBoundingBox();
    },

    _updateLight: function (globeModel, api) {
        var earthMesh = this._earthMesh;

        this._sceneHelper.updateLight(globeModel);
        var mainLight = this._sceneHelper.mainLight;

        // Put sun in the right position
        var time = globeModel.get('light.main.time') || new Date();

        // http://en.wikipedia.org/wiki/Azimuth
        var pos = sunCalc.getPosition(external_echarts_.number.parseDate(time), 0, 0);
        var r0 = Math.cos(pos.altitude);
        // FIXME How to calculate the y ?
        mainLight.position.y = -r0 * Math.cos(pos.azimuth);
        mainLight.position.x = Math.sin(pos.altitude);
        mainLight.position.z = r0 * Math.sin(pos.azimuth);
        mainLight.lookAt(earthMesh.getWorldPosition());
    },

    dispose: function (ecModel, api) {
        this.groupGL.removeAll();
        this._control.dispose();
    }
}));
;// CONCATENATED MODULE: ./src/coord/globe/Globe.js

var Globe_vec3 = dep_glmatrix.vec3;


function Globe(radius) {

    this.radius = radius;

    this.viewGL = null;

    this.altitudeAxis;

    // Displacement data provided by texture.
    this.displacementData = null;
    this.displacementWidth;
    this.displacementHeight;
}

Globe.prototype = {

    constructor: Globe,

    dimensions: ['lng', 'lat', 'alt'],

    type: 'globe',

    containPoint: function () {},

    setDisplacementData: function (data, width, height) {
        this.displacementData = data;
        this.displacementWidth = width;
        this.displacementHeight = height;
    },

    _getDisplacementScale: function (lng, lat) {
        var i = (lng + 180) / 360 * (this.displacementWidth - 1);
        var j = (90 - lat) / 180 * (this.displacementHeight - 1);
        // NEAREST SAMPLING
        // TODO Better bilinear sampling
        var idx = Math.round(i) + Math.round(j) * this.displacementWidth;
        return this.displacementData[idx];
    },

    dataToPoint: function (data, out) {
        var lng = data[0];
        var lat = data[1];
        // Default have 0 altitude
        var altVal = data[2] || 0;

        var r = this.radius;
        if (this.displacementData) {
            r *= 1 + this._getDisplacementScale(lng, lat);
        }
        if (this.altitudeAxis) {
            r += this.altitudeAxis.dataToCoord(altVal);
        }

        lng = lng * Math.PI / 180;
        lat = lat * Math.PI / 180;

        var r0 = Math.cos(lat) * r;

        out = out || [];
        // PENDING
        out[0] = -r0 * Math.cos(lng + Math.PI);
        out[1] = Math.sin(lat) * r;
        out[2] = r0 * Math.sin(lng + Math.PI);

        return out;
    },

    pointToData: function (point, out) {
        var x = point[0];
        var y = point[1];
        var z = point[2];
        var len = Globe_vec3.len(point);
        x /= len;
        y /= len;
        z /= len;

        var theta = Math.asin(y);
        var phi = Math.atan2(z, -x);
        if (phi < 0) {
            phi = Math.PI * 2  + phi;
        }

        var lat = theta * 180 / Math.PI;
        var lng = phi * 180 / Math.PI - 180;

        out = out || [];
        out[0] = lng;
        out[1] = lat;
        out[2] = len - this.radius;
        if (this.altitudeAxis) {
            out[2] = this.altitudeAxis.coordToData(out[2]);
        }

        return out;
    }
};

/* harmony default export */ const globe_Globe = (Globe);
;// CONCATENATED MODULE: ./src/coord/globeCreator.js







function getDisplacementData(img, displacementScale) {
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    var width = img.width;
    var height = img.height;
    canvas.width = width;
    canvas.height = height;
    ctx.drawImage(img, 0, 0, width, height);
    var rgbaArr = ctx.getImageData(0, 0, width, height).data;

    var displacementArr = new Float32Array(rgbaArr.length / 4);
    for (var i = 0; i < rgbaArr.length / 4; i++) {
        var x = rgbaArr[i * 4];
        displacementArr[i] = x / 255 * displacementScale;
    }
    return {
        data: displacementArr,
        width: width,
        height: height
    };
}

function resizeGlobe(globeModel, api) {
    // Use left/top/width/height
    var boxLayoutOption = globeModel.getBoxLayoutParams();

    var viewport = getLayoutRect(boxLayoutOption, {
        width: api.getWidth(),
        height: api.getHeight()
    });

    // Flip Y
    viewport.y = api.getHeight() - viewport.y - viewport.height;

    this.viewGL.setViewport(viewport.x, viewport.y, viewport.width, viewport.height, api.getDevicePixelRatio());

    this.radius = globeModel.get('globeRadius');

    var outerRadius = globeModel.get('globeOuterRadius');
    if (this.altitudeAxis) {
        this.altitudeAxis.setExtent(0, outerRadius - this.radius);
    }
}

function updateGlobe(ecModel, api) {

    var altitudeDataExtent = [Infinity, -Infinity];

    ecModel.eachSeries(function (seriesModel) {
        if (seriesModel.coordinateSystem !== this) {
            return;
        }

        // Get altitude data extent.
        var data = seriesModel.getData();
        var altDims = seriesModel.coordDimToDataDim('alt');
        var altDim = altDims && altDims[0];
        if (altDim) {
            // TODO altitiude is in coords of lines.
            var dataExtent = data.getDataExtent(altDim, true);
            altitudeDataExtent[0] = Math.min(
                altitudeDataExtent[0], dataExtent[0]
            );
            altitudeDataExtent[1] = Math.max(
                altitudeDataExtent[1], dataExtent[1]
            );
        }
    }, this);
    // Create altitude axis
    if (altitudeDataExtent && isFinite(altitudeDataExtent[1] - altitudeDataExtent[0])) {
        var scale = external_echarts_.helper.createScale(
            altitudeDataExtent, {
                type: 'value',
                // PENDING
                min: 'dataMin',
                max: 'dataMax'
            }
        );
        this.altitudeAxis = new external_echarts_.Axis('altitude', scale);
        // Resize again
        this.resize(this.model, api);
    }
}

var globeCreator = {

    dimensions: globe_Globe.prototype.dimensions,

    create: function (ecModel, api) {

        var globeList = [];

        ecModel.eachComponent('globe', function (globeModel) {

            // FIXME
            globeModel.__viewGL = globeModel.__viewGL || new core_ViewGL();

            var globe = new globe_Globe();
            globe.viewGL = globeModel.__viewGL;

            globeModel.coordinateSystem = globe;
            globe.model = globeModel;
            globeList.push(globe);

            // Inject resize
            globe.resize = resizeGlobe;
            globe.resize(globeModel, api);

            globe.update = updateGlobe;
        });

        ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.get('coordinateSystem') === 'globe') {
                var globeModel = seriesModel.getReferringComponents('globe').models[0];
                if (!globeModel) {
                    globeModel = ecModel.getComponent('globe');
                }

                if (!globeModel) {
                    throw new Error('globe "' + util_retrieve.firstNotNull(
                        seriesModel.get('globe3DIndex'),
                        seriesModel.get('globe3DId'),
                        0
                    ) + '" not found');
                }

                var coordSys = globeModel.coordinateSystem;

                seriesModel.coordinateSystem = coordSys;
            }
        });

        ecModel.eachComponent('globe', function (globeModel, idx) {
            var globe = globeModel.coordinateSystem;

            // Update displacement data
            var displacementTextureValue = globeModel.getDisplacementTexture();
            var displacementScale = globeModel.getDisplacemenScale();

            if (globeModel.isDisplacementChanged()) {
                if (globeModel.hasDisplacement()) {
                    var immediateLoaded = true;
                    util_graphicGL.loadTexture(displacementTextureValue, api, function (texture) {
                        var img = texture.image;
                        var displacementData = getDisplacementData(img, displacementScale);
                        globeModel.setDisplacementData(displacementData.data, displacementData.width, displacementData.height);
                        if (!immediateLoaded) {
                            // Update layouts
                            api.dispatchAction({
                                type: 'globeUpdateDisplacment'
                            });
                        }
                    });
                    immediateLoaded = false;
                }
                else {
                    globe.setDisplacementData(null, 0, 0);
                }

                globe.setDisplacementData(
                    globeModel.displacementData, globeModel.displacementWidth, globeModel.displacementHeight
                );
            }
        });

        return globeList;
    }
};

/* harmony default export */ const coord_globeCreator = (globeCreator);
;// CONCATENATED MODULE: ./src/component/globe/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.






function globe_install_install(registers) {
    registers.registerComponentModel(globe_GlobeModel);
    registers.registerComponentView(GlobeView);

    registers.registerCoordinateSystem('globe', coord_globeCreator);

    registers.registerAction({
        type: 'globeChangeCamera',
        event: 'globecamerachanged',
        update: 'series:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'globe', query: payload
        }, function (componentModel) {
            componentModel.setView(payload);
        });
    });

    registers.registerAction({
        type: 'globeUpdateDisplacment',
        event: 'globedisplacementupdated',
        update: 'update'
    }, function (payload, ecModel) {
        // Noop
    });

}
;// CONCATENATED MODULE: ./src/component/globe.js


(0,external_echarts_.use)(globe_install_install);
;// CONCATENATED MODULE: ./src/component/mapbox3D/Mapbox3DModel.js





var MAPBOX_CAMERA_OPTION = ['zoom', 'center', 'pitch', 'bearing'];

var Mapbox3DModel = external_echarts_.ComponentModel.extend({

    type: 'mapbox3D',

    layoutMode: 'box',

    coordinateSystem: null,

    defaultOption: {
        zlevel: -10,

        style: 'mapbox://styles/mapbox/light-v9',

        center: [0, 0],

        zoom: 0,

        pitch: 0,

        bearing: 0,

        light: {
            main: {
                alpha: 20,
                beta: 30
            }
        },

        altitudeScale: 1,
        // Default depend on altitudeScale
        boxHeight: 'auto'
    },

    getMapboxCameraOption: function () {
        var self = this;
        return MAPBOX_CAMERA_OPTION.reduce(function (obj, key) {
            obj[key] = self.get(key);
            return obj;
        }, {});
    },

    setMapboxCameraOption: function (option) {
        if (option != null) {
            MAPBOX_CAMERA_OPTION.forEach(function (key) {
                if (option[key] != null) {
                    this.option[key] = option[key];
                }
            }, this);
        }
    },

    /**
     * Get mapbox instance
     */
    getMapbox: function () {
        return this._mapbox;
    },

    setMapbox: function (mapbox) {
        this._mapbox = mapbox;
    }
});

external_echarts_.util.merge(Mapbox3DModel.prototype, componentPostEffectMixin);
external_echarts_.util.merge(Mapbox3DModel.prototype, componentLightMixin);

/* harmony default export */ const mapbox3D_Mapbox3DModel = (Mapbox3DModel);
;// CONCATENATED MODULE: ./src/component/mapbox3D/Mapbox3DLayer.js
/**
 * @constructor
 * @alias module:echarts-gl/component/mapbox3D/Mapbox3DLayer
 * @param {string} id Layer ID
 * @param {module:zrender/ZRender} zr
 */
function Mapbox3DLayer (id, zr) {
    this.id = id;
    this.zr = zr;

    this.dom = document.createElement('div');
    this.dom.style.cssText = 'position:absolute;left:0;right:0;top:0;bottom:0;';

    // FIXME If in module environment.
    if (!mapboxgl) {
        throw new Error('Mapbox GL library must be included. See https://www.mapbox.com/mapbox-gl-js/api/');
    }

    this._mapbox = new mapboxgl.Map({
        container: this.dom
    });

    // Proxy events
    this._initEvents();

}

Mapbox3DLayer.prototype.setUnpainted = function () {};
Mapbox3DLayer.prototype.resize = function () {
    this._mapbox.resize();
};

Mapbox3DLayer.prototype.getMapbox = function () {
    return this._mapbox;
};

Mapbox3DLayer.prototype.clear = function () {};
Mapbox3DLayer.prototype.refresh = function () {
    this._mapbox.resize();
};

var EVENTS = ['mousedown', 'mouseup', 'click', 'dblclick', 'mousemove',
    'mousewheel', 'wheel',
    'touchstart', 'touchend', 'touchmove', 'touchcancel'
];
Mapbox3DLayer.prototype._initEvents = function () {
    // Event is bound on canvas container.
    var mapboxRoot = this._mapbox.getCanvasContainer();
    this._handlers = this._handlers || {
        contextmenu: function (e) {
            e.preventDefault();
            return false;
        }
    };
    EVENTS.forEach(function (eName) {
        this._handlers[eName] = function (e) {
            var obj = {};
            for (var name in e) {
                obj[name] = e[name];
            }
            obj.bubbles = false;
            var newE = new e.constructor(e.type, obj);
            mapboxRoot.dispatchEvent(newE);
        };
        this.zr.dom.addEventListener(eName, this._handlers[eName]);
    }, this);

    // PENDING
    this.zr.dom.addEventListener('contextmenu', this._handlers.contextmenu);
};

Mapbox3DLayer.prototype.dispose = function () {
    EVENTS.forEach(function (eName) {
        this.zr.dom.removeEventListener(eName, this._handlers[eName]);
    }, this);
};

/* harmony default export */ const mapbox3D_Mapbox3DLayer = (Mapbox3DLayer);
;// CONCATENATED MODULE: ./src/util/shader/displayShadow.glsl.js
/* harmony default export */ const displayShadow_glsl = ("\n@export ecgl.displayShadow.vertex\n\n@import ecgl.common.transformUniforms\n\n@import ecgl.common.uv.header\n\n@import ecgl.common.attributes\n\nvarying vec3 v_WorldPosition;\n\nvarying vec3 v_Normal;\n\nvoid main()\n{\n @import ecgl.common.uv.main\n v_Normal = normalize((worldInverseTranspose * vec4(normal, 0.0)).xyz);\n\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n\n@end\n\n\n@export ecgl.displayShadow.fragment\n\n@import ecgl.common.uv.fragmentHeader\n\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform float roughness: 0.2;\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import ecgl.common.ssaoMap.header\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n float shadow = 1.0;\n\n @import ecgl.common.ssaoMap.main\n\n#if defined(DIRECTIONAL_LIGHT_COUNT) && defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n for (int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++) {\n shadow = min(shadow, shadowContribsDir[i] * 0.5 + 0.5);\n }\n#endif\n\n shadow *= 0.5 + ao * 0.5;\n shadow = clamp(shadow, 0.0, 1.0);\n\n gl_FragColor = vec4(vec3(0.0), 1.0 - shadow);\n}\n\n@end");

;// CONCATENATED MODULE: ./src/component/mapbox3D/Mapbox3DView.js







util_graphicGL.Shader.import(displayShadow_glsl);

var TILE_SIZE = 512;

/* harmony default export */ const Mapbox3DView = (external_echarts_.ComponentView.extend({

    type: 'mapbox3D',

    __ecgl__: true,

    init: function (ecModel, api) {
        var zr = api.getZr();
        this._zrLayer = new mapbox3D_Mapbox3DLayer('mapbox3D', zr);
        zr.painter.insertLayer(-1000, this._zrLayer);

        this._lightRoot = new util_graphicGL.Node();
        this._sceneHelper = new common_SceneHelper(this._lightRoot);
        this._sceneHelper.initLight(this._lightRoot);

        var mapbox = this._zrLayer.getMapbox();
        var dispatchInteractAction = this._dispatchInteractAction.bind(this, api, mapbox);

        // PENDING
        ['zoom', 'rotate', 'drag', 'pitch', 'rotate', 'move'].forEach(function (eName) {
            mapbox.on(eName, dispatchInteractAction);
        });

        this._groundMesh = new util_graphicGL.Mesh({
            geometry: new util_graphicGL.PlaneGeometry(),
            material: new util_graphicGL.Material({
                shader: new util_graphicGL.Shader({
                    vertex: util_graphicGL.Shader.source('ecgl.displayShadow.vertex'),
                    fragment: util_graphicGL.Shader.source('ecgl.displayShadow.fragment')
                }),
                depthMask: false
            }),
            // Render first
            renderOrder: -100,
            culling: false,
            castShadow: false,
            $ignorePicking: true,
            renderNormal: true
        });
    },

    render: function (mapbox3DModel, ecModel, api) {
        var mapbox = this._zrLayer.getMapbox();
        var styleDesc = mapbox3DModel.get('style');

        var styleStr = JSON.stringify(styleDesc);
        if (styleStr !== this._oldStyleStr) {
            if (styleDesc) {
                mapbox.setStyle(styleDesc);
            }
        }
        this._oldStyleStr = styleStr;

        mapbox.setCenter(mapbox3DModel.get('center'));
        mapbox.setZoom(mapbox3DModel.get('zoom'));
        mapbox.setPitch(mapbox3DModel.get('pitch'));
        mapbox.setBearing(mapbox3DModel.get('bearing'));

        mapbox3DModel.setMapbox(mapbox);

        var coordSys = mapbox3DModel.coordinateSystem;

        // Not add to rootNode. Or light direction will be stretched by rootNode scale
        coordSys.viewGL.scene.add(this._lightRoot);
        coordSys.viewGL.add(this._groundMesh);

        this._updateGroundMesh();

        // Update lights
        this._sceneHelper.setScene(coordSys.viewGL.scene);
        this._sceneHelper.updateLight(mapbox3DModel);

        // Update post effects
        coordSys.viewGL.setPostEffect(mapbox3DModel.getModel('postEffect'), api);
        coordSys.viewGL.setTemporalSuperSampling(mapbox3DModel.getModel('temporalSuperSampling'));

        this._mapbox3DModel = mapbox3DModel;
    },

    afterRender: function (mapbox3DModel, ecModel, api, layerGL) {
        var renderer = layerGL.renderer;
        this._sceneHelper.updateAmbientCubemap(renderer, mapbox3DModel, api);
        this._sceneHelper.updateSkybox(renderer, mapbox3DModel, api);

        // FIXME If other series changes coordinate system.
        // FIXME When doing progressive rendering.
        mapbox3DModel.coordinateSystem.viewGL.scene.traverse(function (mesh) {
            if (mesh.material) {
                mesh.material.define('fragment', 'NORMAL_UP_AXIS', 2);
                mesh.material.define('fragment', 'NORMAL_FRONT_AXIS', 1);
            }
        });
    },

    updateCamera: function (mapbox3DModel, ecModel, api, payload) {
        mapbox3DModel.coordinateSystem.setCameraOption(payload);

        this._updateGroundMesh();

        api.getZr().refresh();
    },

    _dispatchInteractAction: function (api, mapbox, mapbox3DModel) {
        api.dispatchAction({
            type: 'mapbox3DChangeCamera',
            pitch: mapbox.getPitch(),
            zoom: mapbox.getZoom(),
            center: mapbox.getCenter().toArray(),
            bearing: mapbox.getBearing(),
            mapbox3DId: this._mapbox3DModel && this._mapbox3DModel.id
        });
    },

    _updateGroundMesh: function () {
        if (this._mapbox3DModel) {
            var coordSys = this._mapbox3DModel.coordinateSystem;
            var pt = coordSys.dataToPoint(coordSys.center);
            this._groundMesh.position.set(pt[0], pt[1], -0.001);

            var plane = new util_graphicGL.Plane(new util_graphicGL.Vector3(0, 0, 1), 0);
            var ray1 = coordSys.viewGL.camera.castRay(new util_graphicGL.Vector2(-1, -1));
            var ray2 = coordSys.viewGL.camera.castRay(new util_graphicGL.Vector2(1, 1));
            var pos0 = ray1.intersectPlane(plane);
            var pos1 = ray2.intersectPlane(plane);
            var scale = pos0.dist(pos1) / coordSys.viewGL.rootNode.scale.x;
            this._groundMesh.scale.set(scale, scale, 1);
        }
    },

    dispose: function (ecModel, api) {
        if (this._zrLayer) {
            this._zrLayer.dispose();
        }
        api.getZr().painter.delLayer(-1000);
    }
}));
;// CONCATENATED MODULE: ./src/coord/mapServiceCommon/MapService3D.js

var MapService3D_mat4 = dep_glmatrix.mat4;

var MapService3D_TILE_SIZE = 512;
var FOV = 0.6435011087932844;
var MapService3D_PI = Math.PI;

var WORLD_SCALE = 1 / 10;

function MapServiceCoordSys3D() {
    /**
     * Width of mapbox viewport
     */
    this.width = 0;
    /**
     * Height of mapbox viewport
     */
    this.height = 0;

    this.altitudeScale = 1;

    // TODO Change boxHeight won't have animation.
    this.boxHeight = 'auto';

    // Set by mapbox creator
    this.altitudeExtent;

    this.bearing = 0;
    this.pitch = 0;
    this.center = [0, 0];

    this._origin;

    this.zoom = 0;
    this._initialZoom;

    // Some parameters for different map services.
    this.maxPitch = 60;
    this.zoomOffset = 0;
}

MapServiceCoordSys3D.prototype = {

    constructor: MapServiceCoordSys3D,

    dimensions: ['lng', 'lat', 'alt'],

    containPoint: function () {},

    setCameraOption: function (option) {
        this.bearing = option.bearing;
        this.pitch = option.pitch;

        this.center = option.center;
        this.zoom = option.zoom;

        if (!this._origin) {
            this._origin = this.projectOnTileWithScale(this.center, MapService3D_TILE_SIZE);
        }
        if (this._initialZoom == null) {
            this._initialZoom = this.zoom;
        }

        this.updateTransform();
    },

    // https://github.com/mapbox/mapbox-gl-js/blob/master/src/geo/transform.js#L479
    updateTransform: function () {
        if (!this.height) { return; }

        var cameraToCenterDistance = 0.5 / Math.tan(FOV / 2) * this.height * WORLD_SCALE;
        // Convert to radian.
        var pitch = Math.max(Math.min(this.pitch, this.maxPitch), 0) / 180 * Math.PI;

        // Find the distance from the center point [width/2, height/2] to the
        // center top point [width/2, 0] in Z units, using the law of sines.
        // 1 Z unit is equivalent to 1 horizontal px at the center of the map
        // (the distance between[width/2, height/2] and [width/2 + 1, height/2])
        var halfFov = FOV / 2;
        var groundAngle = Math.PI / 2 + pitch;
        var topHalfSurfaceDistance = Math.sin(halfFov) * cameraToCenterDistance / Math.sin(Math.PI - groundAngle - halfFov);

        // Calculate z distance of the farthest fragment that should be rendered.
        var furthestDistance = Math.cos(Math.PI / 2 - pitch) * topHalfSurfaceDistance + cameraToCenterDistance;
        // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance`
        var farZ = furthestDistance * 1.1;
        // Forced to be 1000
        if (this.pitch > 50) {
            farZ = 1000;
        }

        // matrix for conversion from location to GL coordinates (-1 .. 1)
        var m = [];
        MapService3D_mat4.perspective(m, FOV, this.width / this.height, 1, farZ);
        this.viewGL.camera.projectionMatrix.setArray(m);
        this.viewGL.camera.decomposeProjectionMatrix();

        var m = MapService3D_mat4.identity([]);
        var pt = this.dataToPoint(this.center);
        // Inverse
        MapService3D_mat4.scale(m, m, [1, -1, 1]);
        // Translate to altitude
        MapService3D_mat4.translate(m, m, [0, 0, -cameraToCenterDistance]);
        MapService3D_mat4.rotateX(m, m, pitch);
        MapService3D_mat4.rotateZ(m, m, -this.bearing / 180 * Math.PI);
        // Translate to center.
        MapService3D_mat4.translate(m, m, [-pt[0] * this.getScale() * WORLD_SCALE, -pt[1] * this.getScale() * WORLD_SCALE, 0]);

        this.viewGL.camera.viewMatrix.array = m;
        var invertM = [];
        MapService3D_mat4.invert(invertM, m);
        this.viewGL.camera.worldTransform.array = invertM;
        this.viewGL.camera.decomposeWorldTransform();

        // scale vertically to meters per pixel (inverse of ground resolution):
        // worldSize / (circumferenceOfEarth * cos(lat * π / 180))
        var worldSize = MapService3D_TILE_SIZE * this.getScale();
        var verticalScale;

        if (this.altitudeExtent && !isNaN(this.boxHeight)) {
            var range = this.altitudeExtent[1] - this.altitudeExtent[0];
            verticalScale = this.boxHeight / range * this.getScale() / Math.pow(2, this._initialZoom - this.zoomOffset);
        }
        else {
            verticalScale = worldSize / (2 * Math.PI * 6378000 * Math.abs(Math.cos(this.center[1] * (Math.PI / 180))))
                * this.altitudeScale * WORLD_SCALE;
        }
        // Include scale to avoid relayout when zooming
        // FIXME Camera scale may have problem in shadow
        this.viewGL.rootNode.scale.set(
            this.getScale() * WORLD_SCALE, this.getScale() * WORLD_SCALE, verticalScale
        );
    },

    getScale: function () {
        return Math.pow(2, this.zoom - this.zoomOffset);
    },

    projectOnTile: function (data, out) {
        return this.projectOnTileWithScale(data, this.getScale() * MapService3D_TILE_SIZE, out);
    },

    projectOnTileWithScale: function (data, scale, out) {
        var lng = data[0];
        var lat = data[1];
        var lambda2 = lng * MapService3D_PI / 180;
        var phi2 = lat * MapService3D_PI / 180;
        var x = scale * (lambda2 + MapService3D_PI) / (2 * MapService3D_PI);
        var y = scale * (MapService3D_PI - Math.log(Math.tan(MapService3D_PI / 4 + phi2 * 0.5))) / (2 * MapService3D_PI);
        out = out || [];
        out[0] = x;
        out[1] = y;
        return out;
    },

    unprojectFromTile: function (point, out) {
        return this.unprojectOnTileWithScale(point, this.getScale() * MapService3D_TILE_SIZE, out);
    },

    unprojectOnTileWithScale: function (point, scale, out) {
        var x = point[0];
        var y = point[1];
        var lambda2 = (x / scale) * (2 * MapService3D_PI) - MapService3D_PI;
        var phi2 = 2 * (Math.atan(Math.exp(MapService3D_PI - (y / scale) * (2 * MapService3D_PI))) - MapService3D_PI / 4);
        out = out || [];
        out[0] = lambda2 * 180 / MapService3D_PI;
        out[1] = phi2 * 180 / MapService3D_PI;
        return out;
    },

    dataToPoint: function (data, out) {
        out = this.projectOnTileWithScale(data, MapService3D_TILE_SIZE, out);
        // Add a origin to avoid precision issue in WebGL.
        out[0] -= this._origin[0];
        out[1] -= this._origin[1];
        // PENDING
        out[2] = !isNaN(data[2]) ? data[2] : 0;
        if (!isNaN(data[2])) {
            out[2] = data[2];
            if (this.altitudeExtent) {
                out[2] -= this.altitudeExtent[0];
            }
        }
        return out;
    }
};

/* harmony default export */ const MapService3D = (MapServiceCoordSys3D);
;// CONCATENATED MODULE: ./src/coord/mapbox3D/Mapbox3D.js


function Mapbox3D() {
    MapService3D.apply(this, arguments);
}

Mapbox3D.prototype = new MapService3D();
Mapbox3D.prototype.constructor = Mapbox3D;
Mapbox3D.prototype.type = 'mapbox3D';

/* harmony default export */ const mapbox3D_Mapbox3D = (Mapbox3D);
;// CONCATENATED MODULE: ./src/coord/mapServiceCommon/createMapService3DCreator.js




/* harmony default export */ function createMapService3DCreator(serviceComponentType, ServiceCtor, afterCreate) {

    function resizeMapService3D(mapService3DModel, api) {
        var width = api.getWidth();
        var height = api.getHeight();
        var dpr = api.getDevicePixelRatio();
        this.viewGL.setViewport(0, 0, width, height, dpr);

        this.width = width;
        this.height = height;

        this.altitudeScale = mapService3DModel.get('altitudeScale');

        this.boxHeight = mapService3DModel.get('boxHeight');
        // this.updateTransform();
    }


    function updateService3D(ecModel, api) {

        if (this.model.get('boxHeight') === 'auto') {
            return;
        }

        var altitudeDataExtent = [Infinity, -Infinity]

        ecModel.eachSeries(function (seriesModel) {
            if (seriesModel.coordinateSystem !== this) {
                return;
            }

            // Get altitude data extent.
            var data = seriesModel.getData();
            var altDim = seriesModel.coordDimToDataDim('alt')[0];
            if (altDim) {
                // TODO altitiude is in coords of lines.
                var dataExtent = data.getDataExtent(altDim, true);
                altitudeDataExtent[0] = Math.min(
                    altitudeDataExtent[0], dataExtent[0]
                );
                altitudeDataExtent[1] = Math.max(
                    altitudeDataExtent[1], dataExtent[1]
                );
            }
        }, this);
        if (altitudeDataExtent && isFinite(altitudeDataExtent[1] - altitudeDataExtent[0])) {
            this.altitudeExtent = altitudeDataExtent;
        }
    }

    return {


        dimensions: ServiceCtor.prototype.dimensions,

        create: function (ecModel, api) {
            var mapService3DList = [];

            ecModel.eachComponent(serviceComponentType, function (mapService3DModel) {
                var viewGL = mapService3DModel.__viewGL;
                if (!viewGL) {
                    viewGL = mapService3DModel.__viewGL = new core_ViewGL();
                    viewGL.setRootNode(new util_graphicGL.Node());
                }

                var mapService3DCoordSys = new ServiceCtor();
                mapService3DCoordSys.viewGL = mapService3DModel.__viewGL;
                // Inject resize
                mapService3DCoordSys.resize = resizeMapService3D;
                mapService3DCoordSys.resize(mapService3DModel, api);

                mapService3DList.push(mapService3DCoordSys);

                mapService3DModel.coordinateSystem = mapService3DCoordSys;
                mapService3DCoordSys.model = mapService3DModel;

                mapService3DCoordSys.update = updateService3D;
            });

            ecModel.eachSeries(function (seriesModel) {
                if (seriesModel.get('coordinateSystem') === serviceComponentType) {
                    var mapService3DModel = seriesModel.getReferringComponents(serviceComponentType).models[0];
                    if (!mapService3DModel) {
                        mapService3DModel = ecModel.getComponent(serviceComponentType);
                    }

                    if (!mapService3DModel) {
                        throw new Error(serviceComponentType + ' "' + util_retrieve.firstNotNull(
                            seriesModel.get(serviceComponentType + 'Index'),
                            seriesModel.get(serviceComponentType + 'Id'),
                            0
                        ) + '" not found');
                    }

                    seriesModel.coordinateSystem = mapService3DModel.coordinateSystem;
                }
            });

            afterCreate && afterCreate(mapService3DList, ecModel, api);

            return mapService3DList;
        }
    };
}

;// CONCATENATED MODULE: ./src/coord/mapbox3DCreator.js



var mapbox3DCreator = createMapService3DCreator('mapbox3D', mapbox3D_Mapbox3D, function (mapbox3DList) {
    mapbox3DList.forEach(function (mapbox3D) {
        mapbox3D.setCameraOption(mapbox3D.model.getMapboxCameraOption());
    });
});

/* harmony default export */ const coord_mapbox3DCreator = (mapbox3DCreator);
;// CONCATENATED MODULE: ./src/component/mapbox3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.






function mapbox3D_install_install(registers) {
    registers.registerComponentModel(mapbox3D_Mapbox3DModel);
    registers.registerComponentView(Mapbox3DView);

    registers.registerCoordinateSystem('mapbox3D', coord_mapbox3DCreator);

    registers.registerAction({
        type: 'mapbox3DChangeCamera',
        event: 'mapbox3dcamerachanged',
        update: 'mapbox3D:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'mapbox3D', query: payload
        }, function (componentModel) {
            componentModel.setMapboxCameraOption(payload);
        });
    });
}
;// CONCATENATED MODULE: ./src/component/mapbox3D.js


(0,external_echarts_.use)(mapbox3D_install_install);
;// CONCATENATED MODULE: ./src/component/maptalks3D/Maptalks3DModel.js





var MAPTALKS_CAMERA_OPTION = ['zoom', 'center', 'pitch', 'bearing'];

var Maptalks3DModel = external_echarts_.ComponentModel.extend({

    type: 'maptalks3D',

    layoutMode: 'box',

    coordinateSystem: null,

    defaultOption: {
        zlevel: -10,

        urlTemplate: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',
        attribution: '&copy; <a href="http://osm.org">OpenStreetMap</a> contributors, &copy; <a href="https://carto.com/">CARTO</a>',

        center: [0, 0],

        zoom: 0,

        pitch: 0,

        bearing: 0,

        light: {
            main: {
                alpha: 20,
                beta: 30
            }
        },

        altitudeScale: 1,
        // Default depend on altitudeScale
        boxHeight: 'auto'
    },

    getMaptalksCameraOption: function () {
        var self = this;
        return MAPTALKS_CAMERA_OPTION.reduce(function (obj, key) {
            obj[key] = self.get(key);
            return obj;
        }, {});
    },

    setMaptalksCameraOption: function (option) {
        if (option != null) {
            MAPTALKS_CAMERA_OPTION.forEach(function (key) {
                if (option[key] != null) {
                    this.option[key] = option[key];
                }
            }, this);
        }
    },

    /**
     * Get maptalks instance
     */
    getMaptalks: function () {
        return this._maptalks;
    },

    setMaptalks: function (maptalks) {
        this._maptalks = maptalks;
    }
});

external_echarts_.util.merge(Maptalks3DModel.prototype, componentPostEffectMixin);
external_echarts_.util.merge(Maptalks3DModel.prototype, componentLightMixin);

/* harmony default export */ const maptalks3D_Maptalks3DModel = (Maptalks3DModel);
;// CONCATENATED MODULE: ./src/component/maptalks3D/Maptalks3DLayer.js
/**
 * @constructor
 * @alias module:echarts-gl/component/maptalks/Maptalks3DLayer
 * @param {string} id Layer ID
 * @param {module:zrender/ZRender} zr
 */
function Maptalks3DLayer (id, zr, defaultCenter, defaultZoom) {
    this.id = id;
    this.zr = zr;

    this.dom = document.createElement('div');
    this.dom.style.cssText = 'position:absolute;left:0;right:0;top:0;bottom:0;';

    // FIXME If in module environment.
    if (!maptalks) {
        throw new Error('Maptalks library must be included. See https://maptalks.org');
    }

    this._maptalks = new maptalks.Map(this.dom, {
        center: defaultCenter,
        zoom: defaultZoom,
        doubleClickZoom:false,
        fog: false
        // fogColor: [0, 0, 0]
    });

    // Proxy events
    this._initEvents();

}

Maptalks3DLayer.prototype.setUnpainted = function () {};
Maptalks3DLayer.prototype.resize = function () {
    this._maptalks.checkSize();
};

Maptalks3DLayer.prototype.getMaptalks = function () {
    return this._maptalks;
};

Maptalks3DLayer.prototype.clear = function () {};
Maptalks3DLayer.prototype.refresh = function () {
    this._maptalks.checkSize();
};

var Maptalks3DLayer_EVENTS = ['mousedown', 'mouseup', 'click', 'dblclick', 'mousemove',
    'mousewheel', 'DOMMouseScroll',
    'touchstart', 'touchend', 'touchmove', 'touchcancel'
];
Maptalks3DLayer.prototype._initEvents = function () {
    // Event is bound on canvas container.
    var maptalksRoot = this.dom;
    this._handlers = this._handlers || {
        contextmenu: function (e) {
            e.preventDefault();
            return false;
        }
    };
    Maptalks3DLayer_EVENTS.forEach(function (eName) {
        this._handlers[eName] = function (e) {
            var obj = {};
            for (var name in e) {
                obj[name] = e[name];
            }
            obj.bubbles = false;
            var newE = new e.constructor(e.type, obj);
            if (eName === 'mousewheel' || eName === 'DOMMouseScroll') {
                // maptalks listens events to different elements?
                maptalksRoot.dispatchEvent(newE);
            }
            else {
                maptalksRoot.firstElementChild.dispatchEvent(newE);
            }
        };
        this.zr.dom.addEventListener(eName, this._handlers[eName]);
    }, this);

    // PENDING
    this.zr.dom.addEventListener('contextmenu', this._handlers.contextmenu);
};

Maptalks3DLayer.prototype.dispose = function () {
    Maptalks3DLayer_EVENTS.forEach(function (eName) {
        this.zr.dom.removeEventListener(eName, this._handlers[eName]);
    }, this);
    this._maptalks.remove();
};

/* harmony default export */ const maptalks3D_Maptalks3DLayer = (Maptalks3DLayer);

;// CONCATENATED MODULE: ./src/component/maptalks3D/Maptalks3DView.js







util_graphicGL.Shader.import(displayShadow_glsl);

/* harmony default export */ const Maptalks3DView = (external_echarts_.ComponentView.extend({

    type: 'maptalks3D',

    __ecgl__: true,

    init: function (ecModel, api) {
        this._groundMesh = new util_graphicGL.Mesh({
            geometry: new util_graphicGL.PlaneGeometry(),
            material: new util_graphicGL.Material({
                shader: new util_graphicGL.Shader({
                    vertex: util_graphicGL.Shader.source('ecgl.displayShadow.vertex'),
                    fragment: util_graphicGL.Shader.source('ecgl.displayShadow.fragment')
                }),
                depthMask: false
            }),
            // Render first
            renderOrder: -100,
            culling: false,
            castShadow: false,
            $ignorePicking: true,
            renderNormal: true
        });
    },

    _initMaptalksLayer: function (mapbox3DModel, api) {
        var zr = api.getZr();
        this._zrLayer = new maptalks3D_Maptalks3DLayer('maptalks3D', zr, mapbox3DModel.get('center'), mapbox3DModel.get('zoom'));
        zr.painter.insertLayer(-1000, this._zrLayer);

        this._lightRoot = new util_graphicGL.Node();
        this._sceneHelper = new common_SceneHelper(this._lightRoot);
        this._sceneHelper.initLight(this._lightRoot);

        var maptalks = this._zrLayer.getMaptalks();
        var dispatchInteractAction = this._dispatchInteractAction.bind(this, api, maptalks);

        // PENDING
        ['zoomend', 'zooming', 'zoomstart', 'dragrotating', 'pitch', 'pitchend', 'movestart',
            'moving', 'moveend', 'resize', 'touchstart', 'touchmove', 'touchend','animating'].forEach(function (eName) {
            maptalks.on(eName, dispatchInteractAction);
        });

    },

    render: function (maptalks3DModel, ecModel, api) {
        if (!this._zrLayer) {
            this._initMaptalksLayer(maptalks3DModel, api);
        }

        var mtks = this._zrLayer.getMaptalks();
        var urlTemplate = maptalks3DModel.get('urlTemplate');

        var baseLayer = mtks.getBaseLayer();
        if (urlTemplate !== this._oldUrlTemplate) {
            if (!baseLayer) {
                baseLayer = new maptalks.TileLayer('maptalks-echarts-gl-baselayer', {
                    urlTemplate: urlTemplate,
                    // used sequentially to help with browser parallel requests per domain limitation
                    subdomains: ['a', 'b', 'c'],
                    attribution: maptalks3DModel.get('attribution')
                });
                mtks.setBaseLayer(baseLayer);
            }
            else {
                // PENDING setOptions may not work?
                baseLayer.setOptions({
                    urlTemplate: urlTemplate,
                    attribution: maptalks3DModel.get('attribution')
                });
            }
        }
        this._oldUrlTemplate = urlTemplate;

        mtks.setCenter(maptalks3DModel.get('center'));
        mtks.setZoom(maptalks3DModel.get('zoom'),{ animation: false });
        mtks.setPitch(maptalks3DModel.get('pitch'));
        mtks.setBearing(maptalks3DModel.get('bearing'));

        maptalks3DModel.setMaptalks(mtks);

        var coordSys = maptalks3DModel.coordinateSystem;

        // Not add to rootNode. Or light direction will be stretched by rootNode scale
        coordSys.viewGL.scene.add(this._lightRoot);
        coordSys.viewGL.add(this._groundMesh);

        this._updateGroundMesh();

        // Update lights
        this._sceneHelper.setScene(coordSys.viewGL.scene);
        this._sceneHelper.updateLight(maptalks3DModel);

        // Update post effects
        coordSys.viewGL.setPostEffect(maptalks3DModel.getModel('postEffect'), api);
        coordSys.viewGL.setTemporalSuperSampling(maptalks3DModel.getModel('temporalSuperSampling'));

        this._maptalks3DModel = maptalks3DModel;
    },

    afterRender: function (maptalks3DModel, ecModel, api, layerGL) {
        var renderer = layerGL.renderer;
        this._sceneHelper.updateAmbientCubemap(renderer, maptalks3DModel, api);
        this._sceneHelper.updateSkybox(renderer, maptalks3DModel, api);

        // FIXME If other series changes coordinate system.
        // FIXME When doing progressive rendering.
        maptalks3DModel.coordinateSystem.viewGL.scene.traverse(function (mesh) {
            if (mesh.material) {
                mesh.material.define('fragment', 'NORMAL_UP_AXIS', 2);
                mesh.material.define('fragment', 'NORMAL_FRONT_AXIS', 1);
            }
        });
    },

    updateCamera: function (maptalks3DModel, ecModel, api, payload) {
        maptalks3DModel.coordinateSystem.setCameraOption(payload);

        this._updateGroundMesh();

        api.getZr().refresh();
    },

    _dispatchInteractAction: function (api, maptalks, maptalks3DModel) {
        api.dispatchAction({
            type: 'maptalks3DChangeCamera',
            pitch: maptalks.getPitch(),
            zoom: getMapboxZoom(maptalks.getResolution()) + 1,
            center: maptalks.getCenter().toArray(),
            bearing: maptalks.getBearing(),
            maptalks3DId: this._maptalks3DModel && this._maptalks3DModel.id
        });
    },

    _updateGroundMesh: function () {
        if (this._maptalks3DModel) {
            var coordSys = this._maptalks3DModel.coordinateSystem;
            var pt = coordSys.dataToPoint(coordSys.center);
            this._groundMesh.position.set(pt[0], pt[1], -0.001);

            var plane = new util_graphicGL.Plane(new util_graphicGL.Vector3(0, 0, 1), 0);
            var ray1 = coordSys.viewGL.camera.castRay(new util_graphicGL.Vector2(-1, -1));
            var ray2 = coordSys.viewGL.camera.castRay(new util_graphicGL.Vector2(1, 1));
            var pos0 = ray1.intersectPlane(plane);
            var pos1 = ray2.intersectPlane(plane);
            var scale = pos0.dist(pos1) / coordSys.viewGL.rootNode.scale.x;
            this._groundMesh.scale.set(scale, scale, 1);
        }
    },

    dispose: function (ecModel, api) {
        if (this._zrLayer) {
            this._zrLayer.dispose();
        }
        api.getZr().painter.delLayer(-1000);
    }
}));

const MAX_RES = 2 * 6378137 * Math.PI / (256 * Math.pow(2, 20));
function getMapboxZoom(res) {
    return 19 - Math.log(res / MAX_RES) / Math.LN2;
}

;// CONCATENATED MODULE: ./src/coord/maptalks3D/Maptalks3D.js


function Maptalks3D() {
    MapService3D.apply(this, arguments);

    this.maxPitch = 85;
    this.zoomOffset = 1;
}

Maptalks3D.prototype = new MapService3D();
Maptalks3D.prototype.constructor = Maptalks3D;
Maptalks3D.prototype.type = 'maptalks3D';

/* harmony default export */ const maptalks3D_Maptalks3D = (Maptalks3D);
;// CONCATENATED MODULE: ./src/coord/maptalks3DCreator.js



var maptalks3DCreator = createMapService3DCreator('maptalks3D', maptalks3D_Maptalks3D, function (maptalks3DList) {
    maptalks3DList.forEach(function (maptalks3D) {
        maptalks3D.setCameraOption(maptalks3D.model.getMaptalksCameraOption());
    });
});

/* harmony default export */ const coord_maptalks3DCreator = (maptalks3DCreator);
;// CONCATENATED MODULE: ./src/component/maptalks3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.






function maptalks3D_install_install(registers) {
    registers.registerComponentModel(maptalks3D_Maptalks3DModel);
    registers.registerComponentView(Maptalks3DView);

    registers.registerCoordinateSystem('maptalks3D', coord_maptalks3DCreator);

    registers.registerAction({
        type: 'maptalks3DChangeCamera',
        event: 'maptalks3dcamerachanged',
        update: 'maptalks3D:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'maptalks3D', query: payload
        }, function (componentModel) {
            componentModel.setMaptalksCameraOption(payload);
        });
    });
}
;// CONCATENATED MODULE: ./src/component/maptalks3D.js
// Thanks to https://gitee.com/iverson_hu/maptalks-echarts-gl


(0,external_echarts_.use)(maptalks3D_install_install);
;// CONCATENATED MODULE: ./src/chart/bar3D/cartesian3DLayout.js


var cartesian3DLayout_vec3 = dep_glmatrix.vec3;
var isDimensionStacked = external_echarts_.helper.dataStack.isDimensionStacked;

function ifCrossZero(extent) {
    var min = extent[0];
    var max = extent[1];
    return !((min > 0 && max > 0) || (min < 0 && max < 0));
};

function cartesian3DLayout(seriesModel, coordSys) {

    var data = seriesModel.getData();
    // var barOnPlane = seriesModel.get('onGridPlane');

    var barSize = seriesModel.get('barSize');
    if (barSize == null) {
        var size = coordSys.size;
        var barWidth;
        var barDepth;
        var xAxis = coordSys.getAxis('x');
        var yAxis = coordSys.getAxis('y');

        if (xAxis.type === 'category') {
            barWidth = xAxis.getBandWidth() * 0.7;
        }
        else {
            // PENDING
            barWidth = Math.round(size[0] / Math.sqrt(data.count())) * 0.6;
        }
        if (yAxis.type === 'category') {
            barDepth = yAxis.getBandWidth() * 0.7;
        }
        else {
            barDepth = Math.round(size[1] / Math.sqrt(data.count())) * 0.6;
        }
        barSize = [barWidth, barDepth];
    }
    else if (!external_echarts_.util.isArray(barSize)) {
        barSize = [barSize, barSize];
    }

    var zAxisExtent = coordSys.getAxis('z').scale.getExtent();
    var ifZAxisCrossZero = ifCrossZero(zAxisExtent);

    var dims = ['x', 'y', 'z'].map(function (coordDimName) {
        return seriesModel.coordDimToDataDim(coordDimName)[0];
    });

    var isStacked = isDimensionStacked(data, dims[2]);
    var valueDim = isStacked
        ? data.getCalculationInfo('stackResultDimension')
        : dims[2];

    data.each(dims, function (x, y, z, idx) {
        // TODO zAxis is inversed
        // TODO On different plane.
        var stackedValue = data.get(valueDim, idx);

        var baseValue = isStacked ? (stackedValue - z)
            : (ifZAxisCrossZero ? 0 : zAxisExtent[0]);

        var start = coordSys.dataToPoint([x, y, baseValue]);
        var end = coordSys.dataToPoint([x, y, stackedValue]);
        var height = cartesian3DLayout_vec3.dist(start, end);
        // PENDING When zAxis is not cross zero.
        var dir = [0, end[1] < start[1] ? -1 : 1, 0];
        if (Math.abs(height) === 0) {
            // TODO
            height = 0.1;
        }
        var size = [barSize[0], height, barSize[1]];
        data.setItemLayout(idx, [start, dir, size]);
    });

    data.setLayout('orient', [1, 0, 0]);
}

/* harmony default export */ const bar3D_cartesian3DLayout = (cartesian3DLayout);
;// CONCATENATED MODULE: ./src/chart/bar3D/evaluateBarSparseness.js
/* harmony default export */ function evaluateBarSparseness(data, dimX, dimY) {
    var xExtent = data.getDataExtent(dimX);
    var yExtent = data.getDataExtent(dimY);

    // TODO Handle one data situation
    var xSpan = (xExtent[1] - xExtent[0]) || xExtent[0];
    var ySpan = (yExtent[1] - yExtent[0]) || yExtent[0];
    var dimSize = 50;
    var tmp = new Uint8Array(dimSize * dimSize);
    for (var i = 0; i < data.count(); i++) {
        var x = data.get(dimX, i);
        var y = data.get(dimY, i);
        var xIdx = Math.floor((x - xExtent[0]) / xSpan * (dimSize - 1));
        var yIdx = Math.floor((y - yExtent[0]) / ySpan * (dimSize - 1));
        var idx = yIdx * dimSize + xIdx;
        tmp[idx] = tmp[idx] || 1;
    }
    var filledCount = 0;
    for (var i = 0; i < tmp.length; i++) {
        if (tmp[i]) {
            filledCount++;
        }
    }
    return filledCount / tmp.length;
};
;// CONCATENATED MODULE: ./src/chart/bar3D/bar3DLayout.js






var bar3DLayout_vec3 = dep_glmatrix.vec3;
var bar3DLayout_isDimensionStacked = external_echarts_.helper.dataStack.isDimensionStacked;

function globeLayout(seriesModel, coordSys) {
    var data = seriesModel.getData();
    var barMinHeight = seriesModel.get('minHeight') || 0;
    var barSize = seriesModel.get('barSize');
    var dims = ['lng', 'lat', 'alt'].map(function (coordDimName) {
        return seriesModel.coordDimToDataDim(coordDimName)[0];
    });
    if (barSize == null) {
        var perimeter = coordSys.radius * Math.PI;
        var fillRatio = evaluateBarSparseness(data, dims[0], dims[1]);
        barSize = [
            perimeter / Math.sqrt(data.count() / fillRatio),
            perimeter / Math.sqrt(data.count() / fillRatio)
        ];
    }
    else if (!external_echarts_.util.isArray(barSize)) {
        barSize = [barSize, barSize];
    }

    var valueDim = getValueDimension(data, dims);

    data.each(dims, function (lng, lat, val, idx) {
        var stackedValue = data.get(valueDim.dimension, idx);
        var baseValue = valueDim.isStacked ? (stackedValue - val) : coordSys.altitudeAxis.scale.getExtent()[0];
        // TODO Stacked with minHeight.
        var height = Math.max(coordSys.altitudeAxis.dataToCoord(val), barMinHeight);
        var start = coordSys.dataToPoint([lng, lat, baseValue]);
        var end = coordSys.dataToPoint([lng, lat, stackedValue]);
        var dir = bar3DLayout_vec3.sub([], end, start);
        bar3DLayout_vec3.normalize(dir, dir);
        var size = [barSize[0], height, barSize[1]];
        data.setItemLayout(idx, [start, dir, size]);
    });

    data.setLayout('orient', math_Vector3.UP.array);
}

function geo3DLayout(seriesModel, coordSys) {
    var data = seriesModel.getData();
    var barSize = seriesModel.get('barSize');
    var barMinHeight = seriesModel.get('minHeight') || 0;
    var dims = ['lng', 'lat', 'alt'].map(function (coordDimName) {
        return seriesModel.coordDimToDataDim(coordDimName)[0];
    });
    if (barSize == null) {
        var size = Math.min(coordSys.size[0], coordSys.size[2]);

        var fillRatio = evaluateBarSparseness(data, dims[0], dims[1]);
        barSize = [
            size / Math.sqrt(data.count() / fillRatio),
            size / Math.sqrt(data.count() / fillRatio)
        ];
    }
    else if (!external_echarts_.util.isArray(barSize)) {
        barSize = [barSize, barSize];
    }
    var dir = [0, 1, 0];

    var valueDim = getValueDimension(data, dims);

    data.each(dims, function (lng, lat, val, idx) {
        var stackedValue = data.get(valueDim.dimension, idx);
        var baseValue = valueDim.isStacked ? (stackedValue - val) : coordSys.altitudeAxis.scale.getExtent()[0];

        var height = Math.max(coordSys.altitudeAxis.dataToCoord(val), barMinHeight);
        var start = coordSys.dataToPoint([lng, lat, baseValue]);
        var size = [barSize[0], height, barSize[1]];
        data.setItemLayout(idx, [start, dir, size]);
    });

    data.setLayout('orient', [1, 0, 0]);
}

function mapService3DLayout(seriesModel, coordSys) {
    var data = seriesModel.getData();
    var dimLng = seriesModel.coordDimToDataDim('lng')[0];
    var dimLat = seriesModel.coordDimToDataDim('lat')[0];
    var dimAlt = seriesModel.coordDimToDataDim('alt')[0];
    var barSize = seriesModel.get('barSize');
    var barMinHeight = seriesModel.get('minHeight') || 0;

    if (barSize == null) {
        var xExtent = data.getDataExtent(dimLng);
        var yExtent = data.getDataExtent(dimLat);
        var corner0 = coordSys.dataToPoint([xExtent[0], yExtent[0]]);
        var corner1 = coordSys.dataToPoint([xExtent[1], yExtent[1]]);

        var size = Math.min(
            Math.abs(corner0[0] - corner1[0]),
            Math.abs(corner0[1] - corner1[1])
        ) || 1;

        var fillRatio = evaluateBarSparseness(data, dimLng, dimLat);
        // PENDING, data density
        barSize = [
            size / Math.sqrt(data.count() / fillRatio),
            size / Math.sqrt(data.count() / fillRatio)
        ];
    }
    else {
        if (!external_echarts_.util.isArray(barSize)) {
            barSize = [barSize, barSize];
        }
        barSize[0] /= coordSys.getScale() / 16;
        barSize[1] /= coordSys.getScale() / 16;
    }

    var dir = [0, 0, 1];
    var dims = [dimLng, dimLat, dimAlt];

    var valueDim = getValueDimension(data, dims);

    data.each(dims, function (lng, lat, val, idx) {
        var stackedValue = data.get(valueDim.dimension, idx);
        var baseValue = valueDim.isStacked ? (stackedValue - val) : 0;

        var start = coordSys.dataToPoint([lng, lat, baseValue]);
        var end = coordSys.dataToPoint([lng, lat, stackedValue]);
        var height = Math.max(end[2] - start[2], barMinHeight);
        var size = [barSize[0], height, barSize[1]];
        data.setItemLayout(idx, [start, dir, size]);
    });

    data.setLayout('orient', [1, 0, 0]);
}

function getValueDimension(data, dataDims) {
    var isStacked = bar3DLayout_isDimensionStacked(data, dataDims[2]);
    return {
        dimension: isStacked
            ? data.getCalculationInfo('stackResultDimension')
            : dataDims[2],
        isStacked: isStacked
    };
}


function registerBarLayout(registers) {
    registers.registerLayout(function (ecModel, api) {
        ecModel.eachSeriesByType('bar3D', function (seriesModel) {
            var coordSys = seriesModel.coordinateSystem;
            var coordSysType = coordSys && coordSys.type;
            if (coordSysType === 'globe') {
                globeLayout(seriesModel, coordSys);
            }
            else if (coordSysType === 'cartesian3D') {
                bar3D_cartesian3DLayout(seriesModel, coordSys);
            }
            else if (coordSysType === 'geo3D') {
                geo3DLayout(seriesModel, coordSys);
            }
            else if (coordSysType === 'mapbox3D' || coordSysType === 'maptalks3D') {
                mapService3DLayout(seriesModel, coordSys);
            }
            else {
                if (true) {
                    if (!coordSys) {
                        throw new Error('bar3D doesn\'t have coordinate system.');
                    }
                    else {
                        throw new Error('bar3D doesn\'t support coordinate system ' + coordSys.type);
                    }
                }
            }
        });
    });
}
;// CONCATENATED MODULE: ./src/util/format.js


var formatUtil = {};
formatUtil.getFormattedLabel = function (seriesModel, dataIndex, status, dataType, dimIndex) {
    status = status || 'normal';
    var data = seriesModel.getData(dataType);
    var itemModel = data.getItemModel(dataIndex);

    var params = seriesModel.getDataParams(dataIndex, dataType);
    if (dimIndex != null && (params.value instanceof Array)) {
        params.value = params.value[dimIndex];
    }

    var formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : ['emphasis', 'label', 'formatter']);
    if (formatter == null) {
        formatter = itemModel.get(['label', 'formatter']);
    }
    var text;
    if (typeof formatter === 'function') {
        params.status = status;
        text = formatter(params);
    }
    else if (typeof formatter === 'string') {
        text = external_echarts_.format.formatTpl(formatter, params);
    }
    return text;
};

/**
 * If value is not array, then convert it to array.
 * @param  {*} value
 * @return {Array} [value] or value
 */
formatUtil.normalizeToArray = function (value) {
    return value instanceof Array
        ? value
        : value == null
        ? []
        : [value];
};

/* harmony default export */ const util_format = (formatUtil);
;// CONCATENATED MODULE: ./src/chart/common/formatTooltip.js



function otherDimToDataDim (data, otherDim) {
    var dataDim = [];
    external_echarts_.util.each(data.dimensions, function (dimName) {
        var dimItem = data.getDimensionInfo(dimName);
        var otherDims = dimItem.otherDims;
        var dimIndex = otherDims[otherDim];
        if (dimIndex != null && dimIndex !== false) {
            dataDim[dimIndex] = dimItem.name;
        }
    });
    return dataDim;
}

/* harmony default export */ function formatTooltip(seriesModel, dataIndex, multipleSeries) {
    function formatArrayValue(value) {
        var vertially = true;

        var result = [];
        var tooltipDims = otherDimToDataDim(data, 'tooltip');

        tooltipDims.length
            ? external_echarts_.util.each(tooltipDims, function (dimIdx) {
                setEachItem(data.get(dimIdx, dataIndex), dimIdx);
            })
            // By default, all dims is used on tooltip.
            : external_echarts_.util.each(value, setEachItem);

        function setEachItem(val, dimIdx) {
            var dimInfo = data.getDimensionInfo(dimIdx);
            // If `dimInfo.tooltip` is not set, show tooltip.
            if (!dimInfo || dimInfo.otherDims.tooltip === false) {
                return;
            }
            var dimType = dimInfo.type;
            var valStr = (vertially ? '- ' + (dimInfo.tooltipName || dimInfo.name) + ': ' : '')
                + (dimType === 'ordinal'
                    ? val + ''
                    : dimType === 'time'
                    ? (multipleSeries ? '' : external_echarts_.format.formatTime('yyyy/MM/dd hh:mm:ss', val))
                    : external_echarts_.format.addCommas(val)
                );
            valStr && result.push(external_echarts_.format.encodeHTML(valStr));
        }

        return (vertially ? '<br/>' : '') + result.join(vertially ? '<br/>' : ', ');
    }

    var data = seriesModel.getData();

    var value = seriesModel.getRawValue(dataIndex);
    var formattedValue = external_echarts_.util.isArray(value)
        ? formatArrayValue(value) : external_echarts_.format.encodeHTML(external_echarts_.format.addCommas(value));
    var name = data.getName(dataIndex);

    var color = getItemVisualColor(data, dataIndex);
    if (external_echarts_.util.isObject(color) && color.colorStops) {
        color = (color.colorStops[0] || {}).color;
    }
    color = color || 'transparent';

    var colorEl = external_echarts_.format.getTooltipMarker(color);

    var seriesName = seriesModel.name;
    // FIXME
    if (seriesName === '\0-') {
        // Not show '-'
        seriesName = '';
    }
    seriesName = seriesName
        ? external_echarts_.format.encodeHTML(seriesName) + (!multipleSeries ? '<br/>' : ': ')
        : '';
    return !multipleSeries
        ? seriesName + colorEl
            + (name
                ? external_echarts_.format.encodeHTML(name) + ': ' + formattedValue
                : formattedValue
            )
        : colorEl + seriesName + formattedValue;
};
;// CONCATENATED MODULE: ./src/chart/common/createList.js


/* harmony default export */ function createList(seriesModel, dims, source) {
    source = source || seriesModel.getSource();

    var coordSysDimensions = dims || external_echarts_.getCoordinateSystemDimensions(seriesModel.get('coordinateSystem')) || ['x', 'y', 'z'];

    var dimensions = external_echarts_.helper.createDimensions(source, {
        dimensionsDefine: source.dimensionsDefine || seriesModel.get('dimensions'),
        encodeDefine: source.encodeDefine || seriesModel.get('encode'),
        coordDimensions: coordSysDimensions.map(function (dim) {
            var axis3DModel = seriesModel.getReferringComponents(dim + 'Axis3D').models[0];
            return {
                type: (axis3DModel && axis3DModel.get('type') === 'category') ? 'ordinal' : 'float',
                name: dim
                // Find stackable dimension. Which will represent value.
                // stackable: dim === 'z'
            };
        })
    });
    if (seriesModel.get('coordinateSystem') === 'cartesian3D') {
        dimensions.forEach(function (dimInfo) {
            if (coordSysDimensions.indexOf(dimInfo.coordDim) >= 0) {
                var axis3DModel = seriesModel.getReferringComponents(dimInfo.coordDim + 'Axis3D').models[0];
                if (axis3DModel && axis3DModel.get('type') === 'category') {
                    dimInfo.ordinalMeta = axis3DModel.getOrdinalMeta();
                }
            }
        });
    }

    var stackCalculationInfo = external_echarts_.helper.dataStack.enableDataStack(
        // Only support 'z' and `byIndex` now.
        seriesModel, dimensions, {byIndex: true, stackedCoordDimension: 'z'}
    );

    var data = new external_echarts_.List(dimensions, seriesModel);

    data.setCalculationInfo(stackCalculationInfo);

    data.initData(source);

    return data;
}
;// CONCATENATED MODULE: ./src/chart/bar3D/Bar3DSeries.js






var Bar3DSeries = external_echarts_.SeriesModel.extend({

    type: 'series.bar3D',

    dependencies: ['globe'],

    visualStyleAccessPathvisu: 'itemStyle',

    getInitialData: function (option, ecModel) {
        return createList(this);
    },

    getFormattedLabel: function (dataIndex, status, dataType, dimIndex) {
        var text = util_format.getFormattedLabel(this, dataIndex, status, dataType, dimIndex);
        if (text == null) {
            text = this.getData().get('z', dataIndex);
        }
        return text;
    },

    formatTooltip: function (dataIndex) {
        return formatTooltip(this, dataIndex);
    },

    defaultOption: {

        coordinateSystem: 'cartesian3D',

        globeIndex: 0,

        grid3DIndex: 0,

        zlevel: -10,

        // bevelSize, 0 has no bevel
        bevelSize: 0,
        // higher is smoother
        bevelSmoothness: 2,

        // Bar width and depth
        // barSize: [1, 1],

        // On grid plane when coordinateSystem is cartesian3D
        onGridPlane: 'xy',

        // Shading of globe
        shading: 'color',

        minHeight: 0,

        itemStyle: {
            opacity: 1
        },

        label: {
            show: false,
            distance: 2,
            textStyle: {
                fontSize: 14,
                color: '#000',
                backgroundColor: 'rgba(255,255,255,0.7)',
                padding: 3,
                borderRadius: 3
            }
        },

        emphasis: {
            label: {
                show: true
            }
        },

        animationDurationUpdate: 500
    }
});

external_echarts_.util.merge(Bar3DSeries.prototype, componentShadingMixin);

/* harmony default export */ const bar3D_Bar3DSeries = (Bar3DSeries);
;// CONCATENATED MODULE: ./src/util/geometry/Bars3DGeometry.js
/**
 * Geometry collecting bars data
 *
 * @module echarts-gl/chart/bars/BarsGeometry
 * @author Yi Shen(http://github.com/pissang)
 */







var Bars3DGeometry_vec3 = dep_glmatrix.vec3;
var Bars3DGeometry_mat3 = dep_glmatrix.mat3;

/**
 * @constructor
 * @alias module:echarts-gl/chart/bars/BarsGeometry
 * @extends clay.Geometry
 */
var BarsGeometry = src_Geometry.extend(function () {
    return {

        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 3, 'POSITION'),
            normal: new src_Geometry.Attribute('normal', 'float', 3, 'NORMAL'),
            color: new src_Geometry.Attribute('color', 'float', 4, 'COLOR'),

            prevPosition: new src_Geometry.Attribute('prevPosition', 'float', 3),
            prevNormal: new src_Geometry.Attribute('prevNormal', 'float', 3)
        },

        dynamic: true,

        enableNormal: false,

        bevelSize: 1,
        bevelSegments: 0,

        // Map from vertexIndex to dataIndex.
        _dataIndices: null,

        _vertexOffset: 0,
        _triangleOffset: 0
    };
},
/** @lends module:echarts-gl/chart/bars/BarsGeometry.prototype */
{

    resetOffset: function () {
        this._vertexOffset = 0;
        this._triangleOffset = 0;
    },

    setBarCount: function (barCount) {
        var enableNormal = this.enableNormal;
        var vertexCount = this.getBarVertexCount() * barCount;
        var triangleCount = this.getBarTriangleCount() * barCount;

        if (this.vertexCount !== vertexCount) {
            this.attributes.position.init(vertexCount);
            if (enableNormal) {
                this.attributes.normal.init(vertexCount);
            }
            else {
                this.attributes.normal.value = null;
            }
            this.attributes.color.init(vertexCount);
        }

        if (this.triangleCount !== triangleCount) {
            this.indices = vertexCount > 0xffff ? new Uint32Array(triangleCount * 3) : new Uint16Array(triangleCount * 3);

            this._dataIndices = new Uint32Array(vertexCount);
        }
    },

    getBarVertexCount: function () {
        var bevelSegments = this.bevelSize > 0 ? this.bevelSegments : 0;
        return bevelSegments > 0 ? this._getBevelBarVertexCount(bevelSegments)
            : (this.enableNormal ? 24 : 8);
    },

    getBarTriangleCount: function () {
        var bevelSegments = this.bevelSize > 0 ? this.bevelSegments : 0;
        return bevelSegments > 0 ? this._getBevelBarTriangleCount(bevelSegments)
            : 12;
    },

    _getBevelBarVertexCount: function (bevelSegments) {
        return (bevelSegments + 1) * 4 * (bevelSegments + 1) * 2;
    },

    _getBevelBarTriangleCount: function (bevelSegments) {
        var widthSegments = bevelSegments * 4 + 3;
        var heightSegments = bevelSegments * 2 + 1;
        return (widthSegments + 1) * heightSegments * 2 + 4;
    },

    setColor: function (idx, color) {
        var vertexCount = this.getBarVertexCount();
        var start = vertexCount * idx;
        var end = vertexCount * (idx + 1);
        for (var i = start; i < end; i++) {
            this.attributes.color.set(i, color);
        }
        this.dirtyAttribute('color');
    },

    /**
     * Get dataIndex of vertex.
     * @param {number} vertexIndex
     */
    getDataIndexOfVertex: function (vertexIndex) {
        return this._dataIndices ? this._dataIndices[vertexIndex] : null;
    },

    /**
     * Add a bar
     * @param {Array.<number>} start
     * @param {Array.<number>} end
     * @param {Array.<number>} orient  right direction
     * @param {Array.<number>} size size on x and z
     * @param {Array.<number>} color
     */
    addBar: (function () {
        var v3Create = Bars3DGeometry_vec3.create;
        var v3ScaleAndAdd = Bars3DGeometry_vec3.scaleAndAdd;

        var end = v3Create();
        var px = v3Create();
        var py = v3Create();
        var pz = v3Create();
        var nx = v3Create();
        var ny = v3Create();
        var nz = v3Create();

        var pts = [];
        var normals = [];
        for (var i = 0; i < 8; i++) {
            pts[i] = v3Create();
        }

        var cubeFaces4 = [
            // PX
            [0, 1, 5, 4],
            // NX
            [2, 3, 7, 6],
            // PY
            [4, 5, 6, 7],
            // NY
            [3, 2, 1, 0],
            // PZ
            [0, 4, 7, 3],
            // NZ
            [1, 2, 6, 5]
        ];
        var face4To3 = [
            0, 1, 2, 0, 2, 3
        ];
        var cubeFaces3 = [];
        for (var i = 0; i < cubeFaces4.length; i++) {
            var face4 = cubeFaces4[i];
            for (var j = 0; j < 2; j++) {
                var face = [];
                for (var k = 0; k < 3; k++) {
                    face.push(face4[face4To3[j * 3 + k]]);
                }
                cubeFaces3.push(face);
            }
        }
        return function (start, dir, leftDir, size, color, dataIndex) {

            // Use vertex, triangle maybe sorted.
            var startVertex = this._vertexOffset;

            if (this.bevelSize > 0 && this.bevelSegments > 0) {
                this._addBevelBar(start, dir, leftDir, size, this.bevelSize, this.bevelSegments, color);
            }
            else {
                Bars3DGeometry_vec3.copy(py, dir);
                Bars3DGeometry_vec3.normalize(py, py);
                // x * y => z
                Bars3DGeometry_vec3.cross(pz, leftDir, py);
                Bars3DGeometry_vec3.normalize(pz, pz);
                // y * z => x
                Bars3DGeometry_vec3.cross(px, py, pz);
                Bars3DGeometry_vec3.normalize(pz, pz);

                Bars3DGeometry_vec3.negate(nx, px);
                Bars3DGeometry_vec3.negate(ny, py);
                Bars3DGeometry_vec3.negate(nz, pz);

                v3ScaleAndAdd(pts[0], start, px, size[0] / 2);
                v3ScaleAndAdd(pts[0], pts[0], pz, size[2] / 2);
                v3ScaleAndAdd(pts[1], start, px, size[0] / 2);
                v3ScaleAndAdd(pts[1], pts[1], nz, size[2] / 2);
                v3ScaleAndAdd(pts[2], start, nx, size[0] / 2);
                v3ScaleAndAdd(pts[2], pts[2], nz, size[2] / 2);
                v3ScaleAndAdd(pts[3], start, nx, size[0] / 2);
                v3ScaleAndAdd(pts[3], pts[3], pz, size[2] / 2);

                v3ScaleAndAdd(end, start, py, size[1]);

                v3ScaleAndAdd(pts[4], end, px, size[0] / 2);
                v3ScaleAndAdd(pts[4], pts[4], pz, size[2] / 2);
                v3ScaleAndAdd(pts[5], end, px, size[0] / 2);
                v3ScaleAndAdd(pts[5], pts[5], nz, size[2] / 2);
                v3ScaleAndAdd(pts[6], end, nx, size[0] / 2);
                v3ScaleAndAdd(pts[6], pts[6], nz, size[2] / 2);
                v3ScaleAndAdd(pts[7], end, nx, size[0] / 2);
                v3ScaleAndAdd(pts[7], pts[7], pz, size[2] / 2);

                var attributes = this.attributes;
                if (this.enableNormal) {
                    normals[0] = px;
                    normals[1] = nx;
                    normals[2] = py;
                    normals[3] = ny;
                    normals[4] = pz;
                    normals[5] = nz;

                    var vertexOffset = this._vertexOffset;
                    for (var i = 0; i < cubeFaces4.length; i++) {
                        var idx3 = this._triangleOffset * 3;
                        for (var k = 0; k < 6; k++) {
                            this.indices[idx3++] = vertexOffset + face4To3[k];
                        }
                        vertexOffset += 4;
                        this._triangleOffset += 2;
                    }

                    for (var i = 0; i < cubeFaces4.length; i++) {
                        var normal = normals[i];
                        for (var k = 0; k < 4; k++) {
                            var idx = cubeFaces4[i][k];
                            attributes.position.set(this._vertexOffset, pts[idx]);
                            attributes.normal.set(this._vertexOffset, normal);
                            attributes.color.set(this._vertexOffset++, color);
                        }
                    }
                }
                else {
                    for (var i = 0; i < cubeFaces3.length; i++) {
                        var idx3 = this._triangleOffset * 3;
                        for (var k = 0; k < 3; k++) {
                            this.indices[idx3 + k] = cubeFaces3[i][k] + this._vertexOffset;
                        }
                        this._triangleOffset++;
                    }

                    for (var i = 0; i < pts.length; i++) {
                        attributes.position.set(this._vertexOffset, pts[i]);
                        attributes.color.set(this._vertexOffset++, color);
                    }
                }
            }

            var endVerex = this._vertexOffset;

            for (var i = startVertex; i < endVerex; i++) {
                this._dataIndices[i] = dataIndex;
            }
        };
    })(),

    /**
     * Add a bar with bevel
     * @param {Array.<number>} start
     * @param {Array.<number>} end
     * @param {Array.<number>} orient  right direction
     * @param {Array.<number>} size size on x and z
     * @param {number} bevelSize
     * @param {number} bevelSegments
     * @param {Array.<number>} color
     */
    _addBevelBar: (function () {
        var px = Bars3DGeometry_vec3.create();
        var py = Bars3DGeometry_vec3.create();
        var pz = Bars3DGeometry_vec3.create();

        var rotateMat = Bars3DGeometry_mat3.create();

        var bevelStartSize = [];

        var xOffsets = [1, -1, -1, 1];
        var zOffsets = [1, 1, -1, -1];
        var yOffsets = [2, 0];

        return function (start, dir, leftDir, size, bevelSize, bevelSegments, color) {
            Bars3DGeometry_vec3.copy(py, dir);
            Bars3DGeometry_vec3.normalize(py, py);
            // x * y => z
            Bars3DGeometry_vec3.cross(pz, leftDir, py);
            Bars3DGeometry_vec3.normalize(pz, pz);
            // y * z => x
            Bars3DGeometry_vec3.cross(px, py, pz);
            Bars3DGeometry_vec3.normalize(pz, pz);

            rotateMat[0] = px[0]; rotateMat[1] = px[1]; rotateMat[2] = px[2];
            rotateMat[3] = py[0]; rotateMat[4] = py[1]; rotateMat[5] = py[2];
            rotateMat[6] = pz[0]; rotateMat[7] = pz[1]; rotateMat[8] = pz[2];

            bevelSize = Math.min(size[0], size[2]) / 2 * bevelSize;

            for (var i = 0; i < 3; i++) {
                bevelStartSize[i] = Math.max(size[i] - bevelSize * 2, 0);
            }
            var rx = (size[0] - bevelStartSize[0]) / 2;
            var ry = (size[1] - bevelStartSize[1]) / 2;
            var rz = (size[2] - bevelStartSize[2]) / 2;

            var pos = [];
            var normal = [];
            var vertexOffset = this._vertexOffset;

            var endIndices = [];
            for (var i = 0; i < 2; i++) {
                endIndices[i] = endIndices[i] = [];

                for (var m = 0; m <= bevelSegments; m++) {
                    for (var j = 0; j < 4; j++) {
                        if ((m === 0 && i === 0) || (i === 1 && m === bevelSegments)) {
                            endIndices[i].push(vertexOffset);
                        }
                        for (var n = 0; n <= bevelSegments; n++) {

                            var phi = n / bevelSegments * Math.PI / 2 + Math.PI / 2 * j;
                            var theta = m / bevelSegments * Math.PI / 2 + Math.PI / 2 * i;
                            // var r = rx < ry ? (rz < rx ? rz : rx) : (rz < ry ? rz : ry);
                            normal[0] = rx * Math.cos(phi) * Math.sin(theta);
                            normal[1] = ry * Math.cos(theta);
                            normal[2] = rz * Math.sin(phi) * Math.sin(theta);
                            pos[0] = normal[0] + xOffsets[j] * bevelStartSize[0] / 2;
                            pos[1] = (normal[1] + ry) + yOffsets[i] * bevelStartSize[1] / 2;
                            pos[2] = normal[2] + zOffsets[j] * bevelStartSize[2] / 2;

                            // Normal is not right if rx, ry, rz not equal.
                            if (!(Math.abs(rx - ry) < 1e-6 && Math.abs(ry - rz) < 1e-6)) {
                                normal[0] /= rx * rx;
                                normal[1] /= ry * ry;
                                normal[2] /= rz * rz;
                            }
                            Bars3DGeometry_vec3.normalize(normal, normal);

                            Bars3DGeometry_vec3.transformMat3(pos, pos, rotateMat);
                            Bars3DGeometry_vec3.transformMat3(normal, normal, rotateMat);
                            Bars3DGeometry_vec3.add(pos, pos, start);

                            this.attributes.position.set(vertexOffset, pos);
                            if (this.enableNormal) {
                                this.attributes.normal.set(vertexOffset, normal);
                            }
                            this.attributes.color.set(vertexOffset, color);
                            vertexOffset++;
                        }
                    }
                }
            }

            var widthSegments = bevelSegments * 4 + 3;
            var heightSegments = bevelSegments * 2 + 1;

            var len = widthSegments + 1;

            for (var j = 0; j < heightSegments; j ++) {
                for (var i = 0; i <= widthSegments; i ++) {
                    var i2 = j * len + i + this._vertexOffset;
                    var i1 = (j * len + (i + 1) % len) + this._vertexOffset;
                    var i4 = (j + 1) * len + (i + 1) % len + this._vertexOffset;
                    var i3 = (j + 1) * len + i + this._vertexOffset;

                    this.setTriangleIndices(this._triangleOffset++, [i4, i2, i1]);
                    this.setTriangleIndices(this._triangleOffset++, [i4, i3, i2]);
                }
            }

            // Close top and bottom
            this.setTriangleIndices(this._triangleOffset++, [endIndices[0][0], endIndices[0][2], endIndices[0][1]]);
            this.setTriangleIndices(this._triangleOffset++, [endIndices[0][0], endIndices[0][3], endIndices[0][2]]);
            this.setTriangleIndices(this._triangleOffset++, [endIndices[1][0], endIndices[1][1], endIndices[1][2]]);
            this.setTriangleIndices(this._triangleOffset++, [endIndices[1][0], endIndices[1][2], endIndices[1][3]]);

            this._vertexOffset = vertexOffset;
        };
    })()
});

external_echarts_.util.defaults(BarsGeometry.prototype, dynamicConvertMixin);
external_echarts_.util.defaults(BarsGeometry.prototype, trianglesSortMixin);

/* harmony default export */ const Bars3DGeometry = (BarsGeometry);
;// CONCATENATED MODULE: ./src/chart/bar3D/Bar3DView.js









var Bar3DView_vec3 = dep_glmatrix.vec3;

/* harmony default export */ const Bar3DView = (external_echarts_.ChartView.extend({

    type: 'bar3D',

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();

        this._api = api;

        this._labelsBuilder = new common_LabelsBuilder(256, 256, api);
        var self = this;
        this._labelsBuilder.getLabelPosition = function (dataIndex, position, distance) {
            if (self._data) {
                var layout = self._data.getItemLayout(dataIndex);
                var start = layout[0];
                var dir = layout[1];
                var height = layout[2][1];
                return Bar3DView_vec3.scaleAndAdd([], start, dir, distance + height);
            }
            else {
                return [0, 0];
            }
        };

        // Give a large render order.
        this._labelsBuilder.getMesh().renderOrder = 100;
    },

    render: function (seriesModel, ecModel, api) {

        // Swap barMesh
        var tmp = this._prevBarMesh;
        this._prevBarMesh = this._barMesh;
        this._barMesh = tmp;

        if (!this._barMesh) {
            this._barMesh = new util_graphicGL.Mesh({
                geometry: new Bars3DGeometry(),
                shadowDepthMaterial: new util_graphicGL.Material({
                    shader: new util_graphicGL.Shader(
                        util_graphicGL.Shader.source('ecgl.sm.depth.vertex'),
                        util_graphicGL.Shader.source('ecgl.sm.depth.fragment')
                    )
                }),
                // Only cartesian3D enable culling
                // FIXME Performance
                culling: seriesModel.coordinateSystem.type === 'cartesian3D',
                // Render after axes
                renderOrder: 10,
                // Render normal in normal pass
                renderNormal: true
            });
        }

        this.groupGL.remove(this._prevBarMesh);
        this.groupGL.add(this._barMesh);
        this.groupGL.add(this._labelsBuilder.getMesh());

        var coordSys = seriesModel.coordinateSystem;
        this._doRender(seriesModel, api);
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);

            var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
            this._barMesh.material[methodName]('fragment', 'SRGB_DECODE');
        }

        this._data = seriesModel.getData();

        this._labelsBuilder.updateData(this._data);

        this._labelsBuilder.updateLabels();

        this._updateAnimation(seriesModel);
    },

    _updateAnimation: function (seriesModel) {
        util_graphicGL.updateVertexAnimation(
            [['prevPosition', 'position'],
            ['prevNormal', 'normal']],
            this._prevBarMesh,
            this._barMesh,
            seriesModel
        );
    },

    _doRender: function (seriesModel, api) {
        var data = seriesModel.getData();
        var shading = seriesModel.get('shading');
        var enableNormal = shading !== 'color';
        var self = this;
        var barMesh = this._barMesh;

        var shadingPrefix = 'ecgl.' + shading;
        if (!barMesh.material || barMesh.material.shader.name !== shadingPrefix) {
            barMesh.material = util_graphicGL.createMaterial(shadingPrefix, ['VERTEX_COLOR']);
        }

        util_graphicGL.setMaterialFromModel(
            shading, barMesh.material, seriesModel, api
        );

        barMesh.geometry.enableNormal = enableNormal;

        barMesh.geometry.resetOffset();

        // Bevel settings
        var bevelSize = seriesModel.get('bevelSize');
        var bevelSegments = seriesModel.get('bevelSmoothness');
        barMesh.geometry.bevelSegments = bevelSegments;

        barMesh.geometry.bevelSize = bevelSize;

        var colorArr = [];
        var vertexColors = new Float32Array(data.count() * 4);
        var colorOffset = 0;
        var barCount = 0;
        var hasTransparent = false;

        data.each(function (idx) {
            if (!data.hasValue(idx)) {
                return;
            }
            var color = getItemVisualColor(data, idx);

            var opacity = getItemVisualOpacity(data, idx);
            if (opacity == null) {
                opacity = 1;
            }

            util_graphicGL.parseColor(color, colorArr);
            colorArr[3] *= opacity;
            vertexColors[colorOffset++] = colorArr[0];
            vertexColors[colorOffset++] = colorArr[1];
            vertexColors[colorOffset++] = colorArr[2];
            vertexColors[colorOffset++] = colorArr[3];

            if (colorArr[3] > 0) {
                barCount++;
                if (colorArr[3] < 0.99) {
                    hasTransparent = true;
                }
            }
        });

        barMesh.geometry.setBarCount(barCount);

        var orient = data.getLayout('orient');

        // Map of dataIndex and barIndex.
        var barIndexOfData = this._barIndexOfData = new Int32Array(data.count());
        var barCount = 0;
        data.each(function (idx) {
            if (!data.hasValue(idx)) {
                barIndexOfData[idx] = -1;
                return;
            }
            var layout = data.getItemLayout(idx);
            var start = layout[0];
            var dir = layout[1];
            var size = layout[2];

            var idx4 = idx * 4;
            colorArr[0] = vertexColors[idx4++];
            colorArr[1] = vertexColors[idx4++];
            colorArr[2] = vertexColors[idx4++];
            colorArr[3] = vertexColors[idx4++];
            if (colorArr[3] > 0) {
                self._barMesh.geometry.addBar(start, dir, orient, size, colorArr, idx);
                barIndexOfData[idx] = barCount++;
            }
        });

        barMesh.geometry.dirty();
        barMesh.geometry.updateBoundingBox();

        var material = barMesh.material;
        material.transparent = hasTransparent;
        material.depthMask = !hasTransparent;
        barMesh.geometry.sortTriangles = hasTransparent;

        this._initHandler(seriesModel, api);
    },

    _initHandler: function (seriesModel, api) {
        var data = seriesModel.getData();
        var barMesh = this._barMesh;
        var isCartesian3D = seriesModel.coordinateSystem.type === 'cartesian3D';

        barMesh.seriesIndex = seriesModel.seriesIndex;

        var lastDataIndex = -1;
        barMesh.off('mousemove');
        barMesh.off('mouseout');
        barMesh.on('mousemove', function (e) {
            var dataIndex = barMesh.geometry.getDataIndexOfVertex(e.triangle[0]);
            if (dataIndex !== lastDataIndex) {
                this._downplay(lastDataIndex);
                this._highlight(dataIndex);
                this._labelsBuilder.updateLabels([dataIndex]);

                if (isCartesian3D) {
                    api.dispatchAction({
                        type: 'grid3DShowAxisPointer',
                        value: [data.get('x', dataIndex), data.get('y', dataIndex), data.get('z', dataIndex, true)]
                    });
                }
            }

            lastDataIndex = dataIndex;
            barMesh.dataIndex = dataIndex;
        }, this);
        barMesh.on('mouseout', function (e) {
            this._downplay(lastDataIndex);
            this._labelsBuilder.updateLabels();
            lastDataIndex = -1;
            barMesh.dataIndex = -1;

            if (isCartesian3D) {
                api.dispatchAction({
                    type: 'grid3DHideAxisPointer'
                });
            }
        }, this);
    },

    _highlight: function (dataIndex) {
        var data = this._data;
        if (!data) {
            return;
        }
        var barIndex = this._barIndexOfData[dataIndex];
        if (barIndex < 0) {
            return;
        }

        var itemModel = data.getItemModel(dataIndex);
        var emphasisItemStyleModel = itemModel.getModel('emphasis.itemStyle');
        var emphasisColor = emphasisItemStyleModel.get('color');
        var emphasisOpacity = emphasisItemStyleModel.get('opacity');
        if (emphasisColor == null) {
            var color = getItemVisualColor(data, dataIndex);
            emphasisColor = external_echarts_.color.lift(color, -0.4);
        }
        if (emphasisOpacity == null) {
            emphasisOpacity = getItemVisualOpacity(data, dataIndex);
        }
        var colorArr = util_graphicGL.parseColor(emphasisColor);
        colorArr[3] *= emphasisOpacity;

        this._barMesh.geometry.setColor(barIndex, colorArr);

        this._api.getZr().refresh();
    },

    _downplay: function (dataIndex) {
        var data = this._data;
        if (!data) {
            return;
        }
        var barIndex = this._barIndexOfData[dataIndex];
        if (barIndex < 0) {
            return;
        }

        var color = getItemVisualColor(data, dataIndex);
        var opacity = getItemVisualOpacity(data, dataIndex);

        var colorArr = util_graphicGL.parseColor(color);
        colorArr[3] *= opacity;

        this._barMesh.geometry.setColor(barIndex, colorArr);

        this._api.getZr().refresh();
    },

    highlight: function (seriesModel, ecModel, api, payload) {
        this._toggleStatus('highlight', seriesModel, ecModel, api, payload);
    },

    downplay: function (seriesModel, ecModel, api, payload) {
        this._toggleStatus('downplay', seriesModel, ecModel, api, payload);
    },

    _toggleStatus: function (status, seriesModel, ecModel, api, payload) {
        var data = seriesModel.getData();
        var dataIndex = util_retrieve.queryDataIndex(data, payload);

        var self = this;
        if (dataIndex != null) {
            external_echarts_.util.each(util_format.normalizeToArray(dataIndex), function (dataIdx) {
                status === 'highlight' ? this._highlight(dataIdx) : this._downplay(dataIdx);
            }, this);
        }
        else {
            data.each(function (dataIdx) {
                status === 'highlight' ? self._highlight(dataIdx) : self._downplay(dataIdx);
            });
        }
    },

    remove: function () {
        this.groupGL.removeAll();
    },

    dispose: function () {
        this._labelsBuilder.dispose();
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/bar3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.







function bar3D_install_install(registers) {
    registers.registerChartView(Bar3DView);
    registers.registerSeriesModel(bar3D_Bar3DSeries);

    registerBarLayout(registers);

    registers.registerProcessor(function (ecModel, api) {
        ecModel.eachSeriesByType('bar3d', function (seriesModel) {
            var data = seriesModel.getData();
            data.filterSelf(function (idx) {
                return data.hasValue(idx);
            });
        });
    });
}
;// CONCATENATED MODULE: ./src/chart/bar3D.js


(0,external_echarts_.use)(bar3D_install_install);
;// CONCATENATED MODULE: ./src/chart/line3D/Line3DSeries.js




var Line3DSeries = external_echarts_.SeriesModel.extend({

    type: 'series.line3D',

    dependencies: ['grid3D'],

    visualStyleAccessPath: 'lineStyle',
    visualDrawType: 'stroke',

    getInitialData: function (option, ecModel) {
        return createList(this);
    },

    formatTooltip: function (dataIndex) {
        return formatTooltip(this, dataIndex);
    },

    defaultOption: {
        coordinateSystem: 'cartesian3D',
        zlevel: -10,

        // Cartesian coordinate system
        grid3DIndex: 0,

        lineStyle: {
            width: 2
        },

        animationDurationUpdate: 500
    }
});

/* harmony default export */ const line3D_Line3DSeries = (Line3DSeries);
;// CONCATENATED MODULE: ./src/chart/line3D/Line3DView.js












var Line3DView_vec3 = dep_glmatrix.vec3;

util_graphicGL.Shader.import(lines3D_glsl);

/* harmony default export */ const Line3DView = (external_echarts_.ChartView.extend({

    type: 'line3D',

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();

        this._api = api;
    },

    render: function (seriesModel, ecModel, api) {
        var tmp = this._prevLine3DMesh;
        this._prevLine3DMesh = this._line3DMesh;
        this._line3DMesh = tmp;

        if (!this._line3DMesh) {
            this._line3DMesh = new util_graphicGL.Mesh({
                geometry: new Lines3D({
                    useNativeLine: false,
                    sortTriangles: true
                }),
                material: new util_graphicGL.Material({
                    shader: util_graphicGL.createShader('ecgl.meshLines3D')
                }),
                // Render after axes
                renderOrder: 10
            });
            this._line3DMesh.geometry.pick = this._pick.bind(this);
        }

        this.groupGL.remove(this._prevLine3DMesh);
        this.groupGL.add(this._line3DMesh);

        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
            // TODO
            var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
            this._line3DMesh.material[methodName]('fragment', 'SRGB_DECODE');
        }
        this._doRender(seriesModel, api);

        this._data = seriesModel.getData();

        this._camera = coordSys.viewGL.camera;

        this.updateCamera();

        this._updateAnimation(seriesModel);
    },

    updateCamera: function () {
        this._updateNDCPosition();
    },

    _doRender: function (seriesModel, api) {
        var data = seriesModel.getData();
        var lineMesh = this._line3DMesh;

        lineMesh.geometry.resetOffset();

        var points = data.getLayout('points');

        var colorArr = [];
        var vertexColors = new Float32Array(points.length / 3 * 4);
        var colorOffset = 0;
        var hasTransparent = false;

        data.each(function (idx) {
            var color = getItemVisualColor(data, idx);
            var opacity = getItemVisualOpacity(data, idx);
            if (opacity == null) {
                opacity = 1;
            }

            util_graphicGL.parseColor(color, colorArr);
            colorArr[3] *= opacity;
            vertexColors[colorOffset++] = colorArr[0];
            vertexColors[colorOffset++] = colorArr[1];
            vertexColors[colorOffset++] = colorArr[2];
            vertexColors[colorOffset++] = colorArr[3];

            if (colorArr[3] < 0.99) {
                hasTransparent = true;
            }
        });

        lineMesh.geometry.setVertexCount(
            lineMesh.geometry.getPolylineVertexCount(points)
        );
        lineMesh.geometry.setTriangleCount(
            lineMesh.geometry.getPolylineTriangleCount(points)
        );

        lineMesh.geometry.addPolyline(
            points, vertexColors,
            util_retrieve.firstNotNull(seriesModel.get('lineStyle.width'), 1)
        );

        lineMesh.geometry.dirty();
        lineMesh.geometry.updateBoundingBox();

        var material = lineMesh.material;
        material.transparent = hasTransparent;
        material.depthMask = !hasTransparent;

        var debugWireframeModel = seriesModel.getModel('debug.wireframe');
        if (debugWireframeModel.get('show')) {
            lineMesh.geometry.createAttribute('barycentric', 'float', 3);
            lineMesh.geometry.generateBarycentric();
            lineMesh.material.set('both', 'WIREFRAME_TRIANGLE');
            lineMesh.material.set(
                'wireframeLineColor', util_graphicGL.parseColor(
                    debugWireframeModel.get('lineStyle.color') || 'rgba(0,0,0,0.5)'
                )
            );
            lineMesh.material.set(
                'wireframeLineWidth', util_retrieve.firstNotNull(
                    debugWireframeModel.get('lineStyle.width'), 1
                )
            );
        }
        else {
            lineMesh.material.set('both', 'WIREFRAME_TRIANGLE');
        }

        this._points = points;

        this._initHandler(seriesModel, api);
    },

    _updateAnimation: function (seriesModel) {
        util_graphicGL.updateVertexAnimation(
            [['prevPosition', 'position'],
            ['prevPositionPrev', 'positionPrev'],
            ['prevPositionNext', 'positionNext']],
            this._prevLine3DMesh,
            this._line3DMesh,
            seriesModel
        );
    },

    _initHandler: function (seriesModel, api) {
        var data = seriesModel.getData();
        var coordSys = seriesModel.coordinateSystem;
        var lineMesh = this._line3DMesh;

        var lastDataIndex = -1;

        lineMesh.seriesIndex = seriesModel.seriesIndex;

        lineMesh.off('mousemove');
        lineMesh.off('mouseout');
        lineMesh.on('mousemove', function (e) {
            var value = coordSys.pointToData(e.point.array);
            var dataIndex = data.indicesOfNearest('x', value[0])[0];
            if (dataIndex !== lastDataIndex) {
                // this._downplay(lastDataIndex);
                // this._highlight(dataIndex);

                api.dispatchAction({
                    type: 'grid3DShowAxisPointer',
                    value: [data.get('x', dataIndex), data.get('y', dataIndex), data.get('z', dataIndex)]
                });

                lineMesh.dataIndex = dataIndex;
            }


            lastDataIndex = dataIndex;
        }, this);
        lineMesh.on('mouseout', function (e) {
            // this._downplay(lastDataIndex);
            lastDataIndex = -1;
            lineMesh.dataIndex = -1;
            api.dispatchAction({
                type: 'grid3DHideAxisPointer'
            });
        }, this);
    },

    // _highlight: function (dataIndex) {
    //     var data = this._data;
    //     if (!data) {
    //         return;
    //     }

    // },

    // _downplay: function (dataIndex) {
    //     var data = this._data;
    //     if (!data) {
    //         return;
    //     }
    // },

    _updateNDCPosition: function () {

        var worldViewProjection = new math_Matrix4();
        var camera = this._camera;
        math_Matrix4.multiply(worldViewProjection, camera.projectionMatrix, camera.viewMatrix);

        var positionNDC = this._positionNDC;
        var points = this._points;
        var nPoints = points.length / 3;
        if (!positionNDC || positionNDC.length / 2 !== nPoints) {
            positionNDC = this._positionNDC = new Float32Array(nPoints * 2);
        }
        var pos = [];
        for (var i = 0; i < nPoints; i++) {
            var i3 = i * 3;
            var i2 = i * 2;
            pos[0] = points[i3];
            pos[1] = points[i3 + 1];
            pos[2] = points[i3 + 2];
            pos[3] = 1;

            Line3DView_vec3.transformMat4(pos, pos, worldViewProjection.array);
            positionNDC[i2] = pos[0] / pos[3];
            positionNDC[i2 + 1] = pos[1] / pos[3];
        }
    },

    _pick: function (x, y, renderer, camera, renderable, out) {
        var positionNDC = this._positionNDC;
        var seriesModel = this._data.hostModel;
        var lineWidth = seriesModel.get('lineStyle.width');

        var dataIndex = -1;
        var width = renderer.viewport.width;
        var height = renderer.viewport.height;

        var halfWidth = width * 0.5;
        var halfHeight = height * 0.5;
        x = (x + 1) * halfWidth;
        y = (y + 1) * halfHeight;

        for (var i = 1; i < positionNDC.length / 2; i++) {
            var x0 = (positionNDC[(i - 1) * 2] + 1) * halfWidth;
            var y0 = (positionNDC[(i - 1) * 2 + 1] + 1) * halfHeight;
            var x1 = (positionNDC[i * 2] + 1) * halfWidth;
            var y1 = (positionNDC[i * 2 + 1] + 1) * halfHeight;

            if (containStroke(x0, y0, x1, y1, lineWidth, x, y)) {
                var dist0 = (x0 - x) * (x0 - x) + (y0 - y) * (y0 - y);
                var dist1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
                // Nearest point.
                dataIndex = dist0 < dist1 ? (i - 1) : i;
            }
        }

        if (dataIndex >= 0) {
            var i3 = dataIndex * 3;
            var point = new math_Vector3(
                this._points[i3],
                this._points[i3 + 1],
                this._points[i3 + 2]
            );

            out.push({
                dataIndex: dataIndex,
                point: point,
                pointWorld: point.clone(),
                target: this._line3DMesh,
                distance: this._camera.getWorldPosition().dist(point)
            });
        }
    },

    remove: function () {
        this.groupGL.removeAll();
    },

    dispose: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/line3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function line3D_install_install(registers) {
    registers.registerChartView(Line3DView);
    registers.registerSeriesModel(line3D_Line3DSeries);

    registers.registerLayout(function (ecModel, api) {
        ecModel.eachSeriesByType('line3D', function (seriesModel) {
            var data = seriesModel.getData();
            var coordSys = seriesModel.coordinateSystem;

            if (coordSys) {
                if (coordSys.type !== 'cartesian3D') {
                    if (true) {
                        console.error('line3D needs cartesian3D coordinateSystem');
                    }
                    return;
                }
                var points = new Float32Array(data.count() * 3);

                var item = [];
                var out = [];

                var coordDims = coordSys.dimensions;
                var dims = coordDims.map(function (coordDim) {
                    return seriesModel.coordDimToDataDim(coordDim)[0];
                });

                if (coordSys) {
                    data.each(dims, function (x, y, z, idx) {
                        item[0] = x;
                        item[1] = y;
                        item[2] = z;

                        coordSys.dataToPoint(item, out);
                        points[idx * 3] = out[0];
                        points[idx * 3 + 1] = out[1];
                        points[idx * 3 + 2] = out[2];
                    });
                }
                data.setLayout('points', points);
            }
        });
    });
}
;// CONCATENATED MODULE: ./src/chart/line3D.js


(0,external_echarts_.use)(line3D_install_install);
;// CONCATENATED MODULE: ./src/chart/scatter3D/Scatter3DSeries.js





/* harmony default export */ const Scatter3DSeries = (external_echarts_.SeriesModel.extend({

    type: 'series.scatter3D',

    dependencies: ['globe', 'grid3D', 'geo3D'],

    visualStyleAccessPath: 'itemStyle',

    hasSymbolVisual: true,

    getInitialData: function (option, ecModel) {
        return createList(this);
    },

    getFormattedLabel: function (dataIndex, status, dataType, dimIndex) {
        var text = util_format.getFormattedLabel(this, dataIndex, status, dataType, dimIndex);
        if (text == null) {
            var data = this.getData();
            var lastDim = data.dimensions[data.dimensions.length - 1];
            text = data.get(lastDim, dataIndex);
        }
        return text;
    },

    formatTooltip: function (dataIndex) {
        return formatTooltip(this, dataIndex);
    },

    defaultOption: {
        coordinateSystem: 'cartesian3D',
        zlevel: -10,

        progressive: 1e5,
        progressiveThreshold: 1e5,

        // Cartesian coordinate system
        grid3DIndex: 0,

        globeIndex: 0,

        symbol: 'circle',
        symbolSize: 10,

        // Support source-over, lighter
        blendMode: 'source-over',

        label: {
            show: false,
            position: 'right',
            // Screen space distance
            distance: 5,

            textStyle: {
                fontSize: 14,
                color: '#000',
                backgroundColor: 'rgba(255,255,255,0.7)',
                padding: 3,
                borderRadius: 3
            }
        },

        itemStyle: {
            opacity: 0.8
        },

        emphasis: {
            label: {
                show: true
            }
        },

        animationDurationUpdate: 500
    }
}));
;// CONCATENATED MODULE: ./src/util/sprite.js


function makeSprite(size, canvas, draw) {
    // http://simonsarris.com/blog/346-how-you-clear-your-canvas-matters
    // http://jsperf.com/canvasclear
    // Set width and height is fast
    // And use the exist canvas if possible
    // http://jsperf.com/create-canvas-vs-set-width-height/2
    var canvas = canvas || document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    var ctx = canvas.getContext('2d');

    draw && draw(ctx);

    return canvas;
}

function sprite_makePath(symbol, symbolSize, style, marginBias) {
    if (!external_echarts_.util.isArray(symbolSize)) {
        symbolSize = [symbolSize, symbolSize];
    }
    var margin = spriteUtil.getMarginByStyle(style, marginBias);
    var width = symbolSize[0] + margin.left + margin.right;
    var height = symbolSize[1] + margin.top + margin.bottom;
    var path = external_echarts_.helper.createSymbol(symbol, 0, 0, symbolSize[0], symbolSize[1]);

    var size = Math.max(width, height);

    path.x = margin.left;
    path.y = margin.top;
    if (width > height) {
        path.y += (size - height) / 2;
    }
    else {
        path.x += (size - width) / 2;
    }

    var rect = path.getBoundingRect();
    path.x -= rect.x;
    path.y -= rect.y;

    path.setStyle(style);

    path.update();

    path.__size = size;

    return path;
}

    // http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
function generateSDF(ctx, sourceImageData, range) {

    var sourceWidth = sourceImageData.width;
    var sourceHeight = sourceImageData.height;

    var width = ctx.canvas.width;
    var height = ctx.canvas.height;

    var scaleX = sourceWidth / width;
    var scaleY = sourceHeight / height;

    function sign(r) {
        return r < 128 ? 1 : -1;
    }
    function searchMinDistance(x, y) {
        var minDistSqr = Infinity;
        x = Math.floor(x * scaleX);
        y = Math.floor(y * scaleY);
        var i = y * sourceWidth + x;
        var r = sourceImageData.data[i * 4];
        var a = sign(r);
        // Search for min distance
        for (var y2 = Math.max(y - range, 0); y2 < Math.min(y + range, sourceHeight); y2++) {
            for (var x2 = Math.max(x - range, 0); x2 < Math.min(x + range, sourceWidth); x2++) {
                var i = y2 * sourceWidth + x2;
                var r2 = sourceImageData.data[i * 4];
                var b = sign(r2);
                var dx = x2 - x;
                var dy = y2 - y;
                if (a !== b) {
                    var distSqr = dx * dx + dy * dy;
                    if (distSqr < minDistSqr) {
                        minDistSqr = distSqr;
                    }
                }
            }
        }
        return a * Math.sqrt(minDistSqr);
    }

    var sdfImageData = ctx.createImageData(width, height);
    for (var y = 0; y < height; y++) {
        for (var x = 0; x < width; x++) {
            var dist = searchMinDistance(x, y);

            var normalized = dist / range * 0.5 + 0.5;
            var i = (y * width + x) * 4;
            sdfImageData.data[i++] = (1.0 - normalized) * 255;
            sdfImageData.data[i++] = (1.0 - normalized) * 255;
            sdfImageData.data[i++] = (1.0 - normalized) * 255;
            sdfImageData.data[i++] = 255;
        }
    }

    return sdfImageData;
}

var spriteUtil = {

    getMarginByStyle: function (style) {
        var minMargin = style.minMargin || 0;

        var lineWidth = 0;
        if (style.stroke && style.stroke !== 'none') {
            lineWidth = style.lineWidth == null ? 1 : style.lineWidth;
        }
        var shadowBlurSize = style.shadowBlur || 0;
        var shadowOffsetX = style.shadowOffsetX || 0;
        var shadowOffsetY = style.shadowOffsetY || 0;

        var margin = {};
        margin.left = Math.max(lineWidth / 2, -shadowOffsetX + shadowBlurSize, minMargin);
        margin.right = Math.max(lineWidth / 2, shadowOffsetX + shadowBlurSize, minMargin);
        margin.top = Math.max(lineWidth / 2, -shadowOffsetY + shadowBlurSize, minMargin);
        margin.bottom = Math.max(lineWidth / 2, shadowOffsetY + shadowBlurSize, minMargin);

        return margin;
    },

    // TODO Not consider shadowOffsetX, shadowOffsetY.
    /**
     * @param {string} symbol
     * @param {number | Array.<number>} symbolSize
     * @param {Object} style
     */
    createSymbolSprite: function (symbol, symbolSize, style, canvas) {
        var path = sprite_makePath(symbol, symbolSize, style);

        var margin = spriteUtil.getMarginByStyle(style);

        return {
            image: makeSprite(path.__size, canvas, function (ctx) {
                external_echarts_.innerDrawElementOnCanvas(ctx, path);
            }),
            margin: margin
        };
    },

    createSDFFromCanvas: function (canvas, size, range, outCanvas) {
        // TODO Create a low resolution SDF from high resolution image.
        return makeSprite(size, outCanvas, function (outCtx) {
            var ctx = canvas.getContext('2d');
            var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);

            outCtx.putImageData(generateSDF(outCtx, imgData, range), 0, 0);
        });
    },

    createSimpleSprite: function (size, canvas) {
        return makeSprite(size, canvas, function (ctx) {
            var halfSize = size / 2;
            ctx.beginPath();
            ctx.arc(halfSize, halfSize, 60, 0, Math.PI * 2, false) ;
            ctx.closePath();

            var gradient = ctx.createRadialGradient(
                halfSize, halfSize, 0, halfSize, halfSize, halfSize
            );
            gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
            gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0.5)');
            gradient.addColorStop(1, 'rgba(255, 255, 255, 0)');
            ctx.fillStyle = gradient;
            ctx.fill();
        });
    }
};

/* harmony default export */ const sprite = (spriteUtil);
;// CONCATENATED MODULE: ./src/util/geometry/verticesSortMixin.js


var verticesSortMixin_vec3 = dep_glmatrix.vec3;

/* harmony default export */ const verticesSortMixin = ({

    needsSortVertices: function () {
        return this.sortVertices;
    },

    needsSortVerticesProgressively: function () {
        return this.needsSortVertices() && this.vertexCount >= 2e4;
    },

    doSortVertices: function (cameraPos, frame) {
        var indices = this.indices;
        var p = verticesSortMixin_vec3.create();

        if (!indices) {
            indices = this.indices = this.vertexCount > 0xffff ? new Uint32Array(this.vertexCount) : new Uint16Array(this.vertexCount);
            for (var i = 0; i < indices.length; i++) {
                indices[i] = i;
            }
        }
        // Do progressive quick sort.
        if (frame === 0) {
            var posAttr = this.attributes.position;
            var cameraPos = cameraPos.array;
            var noneCount = 0;
            if (!this._zList || this._zList.length !== this.vertexCount) {
                this._zList = new Float32Array(this.vertexCount);
            }

            var firstZ;
            for (var i = 0; i < this.vertexCount; i++) {
                posAttr.get(i, p);
                // Camera position is in object space
                var z = verticesSortMixin_vec3.sqrDist(p, cameraPos);
                if (isNaN(z)) {
                    // Put far away, NaN value may cause sort slow
                    z = 1e7;
                    noneCount++;
                }
                if (i === 0) {
                    firstZ = z;
                    z = 0;
                }
                else {
                    // Only store the difference to avoid the precision issue.
                    z = z - firstZ;
                }
                this._zList[i] = z;
            }

            this._noneCount = noneCount;
        }

        if (this.vertexCount < 2e4) {
            // Use simple native sort for simple geometries.
            if (frame === 0) {
                this._simpleSort(this._noneCount / this.vertexCount > 0.05);
            }
        }
        else {
            for (var i = 0; i < 3; i++) {
                this._progressiveQuickSort(frame * 3 + i);
            }
        }

        this.dirtyIndices();
    },

    _simpleSort: function (useNativeQuickSort) {
        var zList = this._zList;
        var indices = this.indices;
        function compare(a, b) {
            // Sort from far to near. which is descending order
            return zList[b] - zList[a];
        }

        // When too much value are equal, using native quick sort with three partition..
        // or the simple quick sort will be nearly O(n*n)
        // http://stackoverflow.com/questions/5126586/quicksort-complexity-when-all-the-elements-are-same

        // Otherwise simple quicksort is more effecient than v8 native quick sort when data all different.
        if (useNativeQuickSort) {
            Array.prototype.sort.call(indices, compare);
        }
        else {
            util_ProgressiveQuickSort.sort(indices, compare, 0, indices.length - 1);
        }
    },

    _progressiveQuickSort: function (frame) {
        var zList = this._zList;
        var indices = this.indices;

        this._quickSort = this._quickSort || new util_ProgressiveQuickSort();

        this._quickSort.step(indices, function (a, b) {
            return zList[b] - zList[a];
        }, frame);
    }
});
;// CONCATENATED MODULE: ./src/chart/common/sdfSprite.glsl.js
/* harmony default export */ const sdfSprite_glsl = ("@export ecgl.sdfSprite.vertex\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform float elapsedTime : 0;\n\nattribute vec3 position : POSITION;\n\n#ifdef VERTEX_SIZE\nattribute float size;\n#else\nuniform float u_Size;\n#endif\n\n#ifdef VERTEX_COLOR\nattribute vec4 a_FillColor: COLOR;\nvarying vec4 v_Color;\n#endif\n\n#ifdef VERTEX_ANIMATION\nattribute vec3 prevPosition;\nattribute float prevSize;\nuniform float percent : 1.0;\n#endif\n\n\n#ifdef POSITIONTEXTURE_ENABLED\nuniform sampler2D positionTexture;\n#endif\n\nvarying float v_Size;\n\nvoid main()\n{\n\n#ifdef POSITIONTEXTURE_ENABLED\n gl_Position = worldViewProjection * vec4(texture2D(positionTexture, position.xy).xy, -10.0, 1.0);\n#else\n\n #ifdef VERTEX_ANIMATION\n vec3 pos = mix(prevPosition, position, percent);\n #else\n vec3 pos = position;\n #endif\n gl_Position = worldViewProjection * vec4(pos, 1.0);\n#endif\n\n#ifdef VERTEX_SIZE\n#ifdef VERTEX_ANIMATION\n v_Size = mix(prevSize, size, percent);\n#else\n v_Size = size;\n#endif\n#else\n v_Size = u_Size;\n#endif\n\n#ifdef VERTEX_COLOR\n v_Color = a_FillColor;\n #endif\n\n gl_PointSize = v_Size;\n}\n\n@end\n\n@export ecgl.sdfSprite.fragment\n\nuniform vec4 color: [1, 1, 1, 1];\nuniform vec4 strokeColor: [1, 1, 1, 1];\nuniform float smoothing: 0.07;\n\nuniform float lineWidth: 0.0;\n\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n\nvarying float v_Size;\n\nuniform sampler2D sprite;\n\n@import clay.util.srgb\n\nvoid main()\n{\n gl_FragColor = color;\n\n vec4 _strokeColor = strokeColor;\n\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n #endif\n\n#ifdef SPRITE_ENABLED\n float d = texture2D(sprite, gl_PointCoord).r;\n gl_FragColor.a *= smoothstep(0.5 - smoothing, 0.5 + smoothing, d);\n\n if (lineWidth > 0.0) {\n float sLineWidth = lineWidth / 2.0;\n\n float outlineMaxValue0 = 0.5 + sLineWidth;\n float outlineMaxValue1 = 0.5 + sLineWidth + smoothing;\n float outlineMinValue0 = 0.5 - sLineWidth - smoothing;\n float outlineMinValue1 = 0.5 - sLineWidth;\n\n if (d <= outlineMaxValue1 && d >= outlineMinValue0) {\n float a = _strokeColor.a;\n if (d <= outlineMinValue1) {\n a = a * smoothstep(outlineMinValue0, outlineMinValue1, d);\n }\n else {\n a = a * smoothstep(outlineMaxValue1, outlineMaxValue0, d);\n }\n gl_FragColor.rgb = mix(gl_FragColor.rgb * gl_FragColor.a, _strokeColor.rgb, a);\n gl_FragColor.a = gl_FragColor.a * (1.0 - a) + a;\n }\n }\n#endif\n\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(gl_FragColor);\n#endif\n}\n@end");

;// CONCATENATED MODULE: ./src/chart/common/PointsMesh.js




var PointsMesh_vec4 = dep_glmatrix.vec4;


util_graphicGL.Shader.import(sdfSprite_glsl);

var PointsMesh = util_graphicGL.Mesh.extend(function () {
    var geometry = new util_graphicGL.Geometry({
        dynamic: true,
        attributes: {
            color: new util_graphicGL.Geometry.Attribute('color', 'float', 4, 'COLOR'),
            position: new util_graphicGL.Geometry.Attribute('position', 'float', 3, 'POSITION'),
            size: new util_graphicGL.Geometry.Attribute('size', 'float', 1),
            prevPosition: new util_graphicGL.Geometry.Attribute('prevPosition', 'float', 3),
            prevSize: new util_graphicGL.Geometry.Attribute('prevSize', 'float', 1)
        }
    });
    Object.assign(geometry, verticesSortMixin);

    var material = new util_graphicGL.Material({
        shader: util_graphicGL.createShader('ecgl.sdfSprite'),
        transparent: true,
        depthMask: false
    });
    material.enableTexture('sprite');
    material.define('both', 'VERTEX_COLOR');
    material.define('both', 'VERTEX_SIZE');

    var sdfTexture = new util_graphicGL.Texture2D({
        image: document.createElement('canvas'),
        flipY: false
    });

    material.set('sprite', sdfTexture);

    // Custom pick methods.
    geometry.pick = this._pick.bind(this);

    return {
        geometry: geometry,
        material: material,
        mode: util_graphicGL.Mesh.POINTS,

        sizeScale: 1
    };
}, {

    _pick: function (x, y, renderer, camera, renderable, out) {
        var positionNDC = this._positionNDC;
        if (!positionNDC) {
            return;
        }

        var viewport = renderer.viewport;
        var ndcScaleX = 2 / viewport.width;
        var ndcScaleY = 2 / viewport.height;
        // From near to far. indices have been sorted.
        for (var i = this.geometry.vertexCount - 1; i >= 0; i--) {
            var idx;
            if (!this.geometry.indices) {
                idx = i;
            }
            else {
                idx = this.geometry.indices[i];
            }

            var cx = positionNDC[idx * 2];
            var cy = positionNDC[idx * 2 + 1];

            var size = this.geometry.attributes.size.get(idx) / this.sizeScale;
            var halfSize = size / 2;

            if (
                x > (cx - halfSize * ndcScaleX) && x < (cx + halfSize * ndcScaleX)
                && y > (cy - halfSize * ndcScaleY) && y < (cy + halfSize * ndcScaleY)
            ) {
                var point = new util_graphicGL.Vector3();
                var pointWorld = new util_graphicGL.Vector3();
                this.geometry.attributes.position.get(idx, point.array);
                util_graphicGL.Vector3.transformMat4(pointWorld, point, this.worldTransform);
                out.push({
                    vertexIndex: idx,
                    point: point,
                    pointWorld: pointWorld,
                    target: this,
                    distance: pointWorld.distance(camera.getWorldPosition())
                });
            }
        }
    },

    updateNDCPosition: function (worldViewProjection, is2D, api) {
        var positionNDC = this._positionNDC;
        var geometry = this.geometry;
        if (!positionNDC || positionNDC.length / 2 !== geometry.vertexCount) {
            positionNDC = this._positionNDC = new Float32Array(geometry.vertexCount * 2);
        }

        var pos = PointsMesh_vec4.create();
        for (var i = 0; i < geometry.vertexCount; i++) {
            geometry.attributes.position.get(i, pos);
            pos[3] = 1;
            PointsMesh_vec4.transformMat4(pos, pos, worldViewProjection.array);
            PointsMesh_vec4.scale(pos, pos, 1 / pos[3]);

            positionNDC[i * 2] = pos[0];
            positionNDC[i * 2 + 1] = pos[1];
        }
    }
});

/* harmony default export */ const common_PointsMesh = (PointsMesh);
;// CONCATENATED MODULE: ./src/chart/common/PointsBuilder.js










var SDF_RANGE = 20;

var Z_2D = -10;

function isSymbolSizeSame(a, b) {
    return a && b && a[0] === b[0] && a[1] === b[1];
}
// TODO gl_PointSize has max value.
function PointsBuilder(is2D, api) {
    this.rootNode = new util_graphicGL.Node();

    /**
     * @type {boolean}
     */
    this.is2D = is2D;

    this._labelsBuilder = new common_LabelsBuilder(256, 256, api);

    // Give a large render order.
    this._labelsBuilder.getMesh().renderOrder = 100;
    this.rootNode.add(this._labelsBuilder.getMesh());

    this._api = api;

    this._spriteImageCanvas = document.createElement('canvas');

    this._startDataIndex = 0;
    this._endDataIndex = 0;

    this._sizeScale = 1;
}

PointsBuilder.prototype = {

    constructor: PointsBuilder,

    /**
     * If highlight on over
     */
    highlightOnMouseover: true,

    update: function (seriesModel, ecModel, api, start, end) {
        // Swap barMesh
        var tmp = this._prevMesh;
        this._prevMesh = this._mesh;
        this._mesh = tmp;

        var data = seriesModel.getData();

        if (start == null) {
            start = 0;
        }
        if (end == null) {
            end = data.count();
        }
        this._startDataIndex = start;
        this._endDataIndex = end - 1;

        if (!this._mesh) {
            var material = this._prevMesh && this._prevMesh.material;
            this._mesh = new common_PointsMesh({
                // Render after axes
                renderOrder: 10,
                // FIXME
                frustumCulling: false
            });
            if (material) {
                this._mesh.material = material;
            }
        }
        var material = this._mesh.material;
        var geometry = this._mesh.geometry;
        var attributes = geometry.attributes;

        this.rootNode.remove(this._prevMesh);
        this.rootNode.add(this._mesh);

        this._setPositionTextureToMesh(this._mesh, this._positionTexture);

        var symbolInfo = this._getSymbolInfo(seriesModel, start, end);
        var dpr = api.getDevicePixelRatio();

        // TODO image symbol
        var itemStyle = seriesModel.getModel('itemStyle').getItemStyle();
        var largeMode = seriesModel.get('large');

        var pointSizeScale = 1;
        if (symbolInfo.maxSize > 2) {
            pointSizeScale = this._updateSymbolSprite(seriesModel, itemStyle, symbolInfo, dpr);
            material.enableTexture('sprite');
        }
        else {
            material.disableTexture('sprite');
        }

        attributes.position.init(end - start);
        var rgbaArr = [];
        if (largeMode) {
            material.undefine('VERTEX_SIZE');
            material.undefine('VERTEX_COLOR');

            var color = getVisualColor(data);
            var opacity = getVisualOpacity(data);
            util_graphicGL.parseColor(color, rgbaArr);
            rgbaArr[3] *= opacity;

            material.set({
                color: rgbaArr,
                'u_Size': symbolInfo.maxSize * this._sizeScale
            });
        }
        else {
            material.set({
                color: [1, 1, 1, 1]
            });
            material.define('VERTEX_SIZE');
            material.define('VERTEX_COLOR');
            attributes.size.init(end - start);
            attributes.color.init(end - start);
            this._originalOpacity = new Float32Array(end - start);
        }

        var points = data.getLayout('points');

        var positionArr = attributes.position.value;

        var hasTransparentPoint = false;

        for (var i = 0; i < end - start; i++) {
            var i3 = i * 3;
            var i2 = i * 2;
            if (this.is2D) {
                positionArr[i3] = points[i2];
                positionArr[i3 + 1] = points[i2 + 1];
                positionArr[i3 + 2] = Z_2D;
            }
            else {
                positionArr[i3] = points[i3];
                positionArr[i3 + 1] = points[i3 + 1];
                positionArr[i3 + 2] = points[i3 + 2];
            }

            if (!largeMode) {
                var color = getItemVisualColor(data, i);
                var opacity = getItemVisualOpacity(data, i);
                util_graphicGL.parseColor(color, rgbaArr);
                rgbaArr[3] *= opacity;
                attributes.color.set(i, rgbaArr);
                if (rgbaArr[3] < 0.99) {
                    hasTransparentPoint = true;
                }
                var symbolSize = data.getItemVisual(i, 'symbolSize');
                symbolSize = (symbolSize instanceof Array
                    ? Math.max(symbolSize[0], symbolSize[1]) : symbolSize);

                // NaN pointSize may have strange result.
                if (isNaN(symbolSize)) {
                    symbolSize = 0;
                }
                // Scale point size because canvas has margin.
                attributes.size.value[i] = symbolSize * pointSizeScale * this._sizeScale;

                // Save the original opacity for recover from fadeIn.
                this._originalOpacity[i] = rgbaArr[3];
            }

        }

        this._mesh.sizeScale = pointSizeScale;

        geometry.updateBoundingBox();
        geometry.dirty();

        // Update material.
        this._updateMaterial(seriesModel, itemStyle);

        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
            material[methodName]('fragment', 'SRGB_DECODE');
        }

        if (!largeMode) {
            this._updateLabelBuilder(seriesModel, start, end);
        }

        this._updateHandler(seriesModel, ecModel, api);

        this._updateAnimation(seriesModel);

        this._api = api;
    },

    getPointsMesh: function () {
        return this._mesh;
    },

    updateLabels: function (highlightDataIndices) {
        this._labelsBuilder.updateLabels(highlightDataIndices);
    },

    hideLabels: function () {
        this.rootNode.remove(this._labelsBuilder.getMesh());
    },

    showLabels: function () {
        this.rootNode.add(this._labelsBuilder.getMesh());
    },

    dispose: function () {
        this._labelsBuilder.dispose();
    },

    _updateSymbolSprite: function (seriesModel, itemStyle, symbolInfo, dpr) {
        symbolInfo.maxSize = Math.min(symbolInfo.maxSize * 2, 200);
        var symbolSize = [];
        if (symbolInfo.aspect > 1) {
            symbolSize[0] = symbolInfo.maxSize;
            symbolSize[1] = symbolInfo.maxSize / symbolInfo.aspect;
        }
        else {
            symbolSize[1] = symbolInfo.maxSize;
            symbolSize[0] = symbolInfo.maxSize * symbolInfo.aspect;
        }

        // In case invalid data.
        symbolSize[0] = symbolSize[0] || 1;
        symbolSize[1] = symbolSize[1] || 1;

        if (this._symbolType !== symbolInfo.type
            || !isSymbolSizeSame(this._symbolSize, symbolSize)
            || this._lineWidth !== itemStyle.lineWidth
        ) {
            sprite.createSymbolSprite(symbolInfo.type, symbolSize, {
                fill: '#fff',
                lineWidth: itemStyle.lineWidth,
                stroke: 'transparent',
                shadowColor: 'transparent',
                minMargin: Math.min(symbolSize[0] / 2, 10)
            }, this._spriteImageCanvas);

            sprite.createSDFFromCanvas(
                this._spriteImageCanvas, Math.min(this._spriteImageCanvas.width, 32), SDF_RANGE,
                this._mesh.material.get('sprite').image
            );

            this._symbolType = symbolInfo.type;
            this._symbolSize = symbolSize;
            this._lineWidth = itemStyle.lineWidth;
        }
        return this._spriteImageCanvas.width / symbolInfo.maxSize * dpr;

    },

    _updateMaterial: function (seriesModel, itemStyle) {
        var blendFunc = seriesModel.get('blendMode') === 'lighter'
            ? util_graphicGL.additiveBlend : null;
        var material = this._mesh.material;
        material.blend = blendFunc;

        material.set('lineWidth', itemStyle.lineWidth / SDF_RANGE);

        var strokeColor = util_graphicGL.parseColor(itemStyle.stroke);
        material.set('strokeColor', strokeColor);

        // Because of symbol texture, we always needs it be transparent.
        material.transparent = true;
        material.depthMask = false;
        material.depthTest = !this.is2D;
        material.sortVertices = !this.is2D;
    },

    _updateLabelBuilder: function (seriesModel, start, end) {
        var data =seriesModel.getData();
        var geometry = this._mesh.geometry;
        var positionArr = geometry.attributes.position.value;
        var start = this._startDataIndex;
        var pointSizeScale = this._mesh.sizeScale;
        this._labelsBuilder.updateData(data, start, end);

        this._labelsBuilder.getLabelPosition = function (dataIndex, positionDesc, distance) {
            var idx3 = (dataIndex - start) * 3;
            return [positionArr[idx3], positionArr[idx3 + 1], positionArr[idx3 + 2]];
        };

        this._labelsBuilder.getLabelDistance = function (dataIndex, positionDesc, distance) {
            var size = geometry.attributes.size.get(dataIndex - start) / pointSizeScale;
            return size / 2 + distance;
        };
        this._labelsBuilder.updateLabels();

    },

    _updateAnimation: function (seriesModel) {
        util_graphicGL.updateVertexAnimation(
            [['prevPosition', 'position'],
            ['prevSize', 'size']],
            this._prevMesh,
            this._mesh,
            seriesModel
        );
    },

    _updateHandler: function (seriesModel, ecModel, api) {
        var data = seriesModel.getData();
        var pointsMesh = this._mesh;
        var self = this;

        var lastDataIndex = -1;
        var isCartesian3D = seriesModel.coordinateSystem
            && seriesModel.coordinateSystem.type === 'cartesian3D';

        var grid3DModel;
        if (isCartesian3D) {
            grid3DModel = seriesModel.coordinateSystem.model;
        }

        pointsMesh.seriesIndex = seriesModel.seriesIndex;

        pointsMesh.off('mousemove');
        pointsMesh.off('mouseout');

        pointsMesh.on('mousemove', function (e) {
            var dataIndex = e.vertexIndex + self._startDataIndex;
            if (dataIndex !== lastDataIndex) {
                if (this.highlightOnMouseover) {
                    this.downplay(data, lastDataIndex);
                    this.highlight(data, dataIndex);
                    this._labelsBuilder.updateLabels([dataIndex]);
                }

                if (isCartesian3D) {
                    api.dispatchAction({
                        type: 'grid3DShowAxisPointer',
                        value: [
                            data.get(seriesModel.coordDimToDataDim('x')[0], dataIndex),
                            data.get(seriesModel.coordDimToDataDim('y')[0], dataIndex),
                            data.get(seriesModel.coordDimToDataDim('z')[0], dataIndex)
                        ],
                        grid3DIndex: grid3DModel.componentIndex
                    });
                }
            }

            pointsMesh.dataIndex = dataIndex;
            lastDataIndex = dataIndex;
        }, this);
        pointsMesh.on('mouseout', function (e) {
            var dataIndex = e.vertexIndex + self._startDataIndex;
            if (this.highlightOnMouseover) {
                this.downplay(data, dataIndex);
                this._labelsBuilder.updateLabels();
            }
            lastDataIndex = -1;
            pointsMesh.dataIndex = -1;

            if (isCartesian3D) {
                api.dispatchAction({
                    type: 'grid3DHideAxisPointer',
                    grid3DIndex: grid3DModel.componentIndex
                });
            }
        }, this);
    },

    updateLayout: function (seriesModel, ecModel, api) {
        var data = seriesModel.getData();
        if (!this._mesh) {
            return;
        }

        var positionArr = this._mesh.geometry.attributes.position.value;
        var points = data.getLayout('points');
        if (this.is2D) {
            for (var i = 0; i < points.length / 2; i++) {
                var i3 = i * 3;
                var i2 = i * 2;
                positionArr[i3] = points[i2];
                positionArr[i3 + 1] = points[i2 + 1];
                positionArr[i3 + 2] = Z_2D;
            }
        }
        else {
            for (var i = 0; i < points.length; i++) {
                positionArr[i] = points[i];
            }
        }
        this._mesh.geometry.dirty();

        api.getZr().refresh();
    },

    updateView: function (camera) {
        if (!this._mesh) {
            return;
        }

        var worldViewProjection = new math_Matrix4();
        math_Matrix4.mul(worldViewProjection, camera.viewMatrix, this._mesh.worldTransform);
        math_Matrix4.mul(worldViewProjection, camera.projectionMatrix, worldViewProjection);

        this._mesh.updateNDCPosition(worldViewProjection, this.is2D, this._api);
    },

    highlight: function (data, dataIndex) {
        if (dataIndex > this._endDataIndex || dataIndex < this._startDataIndex) {
            return;
        }
        var itemModel = data.getItemModel(dataIndex);
        var emphasisItemStyleModel = itemModel.getModel('emphasis.itemStyle');
        var emphasisColor = emphasisItemStyleModel.get('color');
        var emphasisOpacity = emphasisItemStyleModel.get('opacity');
        if (emphasisColor == null) {
            var color = getItemVisualColor(data, dataIndex);
            emphasisColor = external_echarts_.color.lift(color, -0.4);
        }
        if (emphasisOpacity == null) {
            emphasisOpacity = getItemVisualOpacity(data, dataIndex);
        }
        var colorArr = util_graphicGL.parseColor(emphasisColor);
        colorArr[3] *= emphasisOpacity;

        this._mesh.geometry.attributes.color.set(dataIndex - this._startDataIndex, colorArr);
        this._mesh.geometry.dirtyAttribute('color');

        this._api.getZr().refresh();
    },

    downplay: function (data, dataIndex) {
        if (dataIndex > this._endDataIndex || dataIndex < this._startDataIndex) {
            return;
        }
        var color = getItemVisualColor(data, dataIndex);
        var opacity = getItemVisualOpacity(data, dataIndex);

        var colorArr = util_graphicGL.parseColor(color);
        colorArr[3] *= opacity;

        this._mesh.geometry.attributes.color.set(dataIndex - this._startDataIndex, colorArr);
        this._mesh.geometry.dirtyAttribute('color');

        this._api.getZr().refresh();
    },

    fadeOutAll: function (fadeOutPercent) {
        if (this._originalOpacity) {
            var geo = this._mesh.geometry;
            for (var i = 0; i < geo.vertexCount; i++) {
                var fadeOutOpacity = this._originalOpacity[i] * fadeOutPercent;
                geo.attributes.color.value[i * 4 + 3] = fadeOutOpacity;
            }
            geo.dirtyAttribute('color');

            this._api.getZr().refresh();
        }
    },

    fadeInAll: function () {
        this.fadeOutAll(1);
    },

    setPositionTexture: function (texture) {
        if (this._mesh) {
            this._setPositionTextureToMesh(this._mesh, texture);
        }

        this._positionTexture = texture;
    },

    removePositionTexture: function () {
        this._positionTexture = null;
        if (this._mesh) {
            this._setPositionTextureToMesh(this._mesh, null);
        }
    },

    setSizeScale: function (sizeScale) {
        if (sizeScale !== this._sizeScale) {
            if (this._mesh) {
                var originalSize = this._mesh.material.get('u_Size');
                this._mesh.material.set('u_Size', originalSize / this._sizeScale * sizeScale);

                var attributes = this._mesh.geometry.attributes;
                if (attributes.size.value) {
                    for (var i = 0; i < attributes.size.value.length; i++) {
                        attributes.size.value[i] = attributes.size.value[i] / this._sizeScale * sizeScale;
                    }
                }
            }
            this._sizeScale = sizeScale;
        }
    },

    _setPositionTextureToMesh: function (mesh, texture) {
        if (texture) {
            mesh.material.set('positionTexture', texture);
        }
        mesh.material[
            texture ? 'enableTexture' : 'disableTexture'
        ]('positionTexture');
    },

    _getSymbolInfo: function (seriesModel, start, end) {
        if (seriesModel.get('large')) {
            var symbolSize = util_retrieve.firstNotNull(seriesModel.get('symbolSize'), 1);
            var maxSymbolSize;
            var symbolAspect;
            if (symbolSize instanceof Array) {
                maxSymbolSize = Math.max(symbolSize[0], symbolSize[1]);
                symbolAspect = symbolSize[0] / symbolSize[1];
            }
            else {
                maxSymbolSize = symbolSize;
                symbolAspect = 1;
            }
            return {
                maxSize: symbolSize,
                type: seriesModel.get('symbol'),
                aspect: symbolAspect
            }
        }
        var data = seriesModel.getData();
        var symbolAspect;
        var differentSymbolAspect = false;
        var symbolType = data.getItemVisual(0, 'symbol') || 'circle';
        var differentSymbolType = false;
        var maxSymbolSize = 0;

        for (var idx = start; idx < end; idx++) {
            var symbolSize = data.getItemVisual(idx, 'symbolSize');
            var currentSymbolType = data.getItemVisual(idx, 'symbol');
            var currentSymbolAspect;
            if (!(symbolSize instanceof Array)) {
                // Ignore NaN value.
                if (isNaN(symbolSize)) {
                    continue;
                }

                currentSymbolAspect = 1;
                maxSymbolSize = Math.max(symbolSize, maxSymbolSize);
            }
            else {
                currentSymbolAspect = symbolSize[0] / symbolSize[1];
                maxSymbolSize = Math.max(Math.max(symbolSize[0], symbolSize[1]), maxSymbolSize);
            }
            if (true) {
                if (symbolAspect != null && Math.abs(currentSymbolAspect - symbolAspect) > 0.05) {
                    differentSymbolAspect = true;
                }
                if (currentSymbolType !== symbolType) {
                    differentSymbolType = true;
                }
            }
            symbolType = currentSymbolType;
            symbolAspect = currentSymbolAspect;
        }

        if (true) {
            if (differentSymbolAspect) {
                console.warn('Different symbol width / height ratio will be ignored.');
            }
            if (differentSymbolType) {
                console.warn('Different symbol type will be ignored.');
            }
        }

        return {
            maxSize: maxSymbolSize,
            type: symbolType,
            aspect: symbolAspect
        };
    }
};

/* harmony default export */ const common_PointsBuilder = (PointsBuilder);

;// CONCATENATED MODULE: ./src/chart/scatter3D/Scatter3DView.js







/* harmony default export */ const Scatter3DView = (external_echarts_.ChartView.extend({

    type: 'scatter3D',

    hasSymbolVisual: true,

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();

        this._pointsBuilderList = [];
        this._currentStep = 0;
    },

    render: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();
        if (!seriesModel.getData().count()) {
            return;
        }

        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
            this._camera = coordSys.viewGL.camera;

            var pointsBuilder = this._pointsBuilderList[0];
            if (!pointsBuilder) {
                pointsBuilder = this._pointsBuilderList[0] = new common_PointsBuilder(false, api);
            }
            this._pointsBuilderList.length = 1;

            this.groupGL.add(pointsBuilder.rootNode);
            pointsBuilder.update(seriesModel, ecModel, api);
            pointsBuilder.updateView(coordSys.viewGL.camera);
        }
        else {
            if (true) {
                throw new Error('Invalid coordinate system');
            }
        }
    },

    incrementalPrepareRender: function (seriesModel, ecModel, api) {
        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
            this._camera = coordSys.viewGL.camera;
        }
        else {
            if (true) {
                throw new Error('Invalid coordinate system');
            }
        }

        this.groupGL.removeAll();
        this._currentStep = 0;
    },

    incrementalRender: function (params, seriesModel, ecModel, api) {
        // TODO Sort transparency.
        if (params.end <= params.start) {
            return;
        }
        var pointsBuilder = this._pointsBuilderList[this._currentStep];
        if (!pointsBuilder) {
            pointsBuilder = new common_PointsBuilder(false, api);
            this._pointsBuilderList[this._currentStep] = pointsBuilder;
        }
        this.groupGL.add(pointsBuilder.rootNode);

        pointsBuilder.update(seriesModel, ecModel, api, params.start, params.end);
        pointsBuilder.updateView(seriesModel.coordinateSystem.viewGL.camera);

        this._currentStep++;
    },

    updateCamera: function () {
        this._pointsBuilderList.forEach(function (pointsBuilder) {
            pointsBuilder.updateView(this._camera);
        }, this);
    },

    highlight: function (seriesModel, ecModel, api, payload) {
        this._toggleStatus('highlight', seriesModel, ecModel, api, payload);
    },

    downplay: function (seriesModel, ecModel, api, payload) {
        this._toggleStatus('downplay', seriesModel, ecModel, api, payload);
    },

    _toggleStatus: function (status, seriesModel, ecModel, api, payload) {
        var data = seriesModel.getData();
        var dataIndex = util_retrieve.queryDataIndex(data, payload);

        var isHighlight = status === 'highlight';
        if (dataIndex != null) {
            external_echarts_.util.each(util_format.normalizeToArray(dataIndex), function (dataIdx) {
                for (var i = 0; i < this._pointsBuilderList.length; i++) {
                    var pointsBuilder = this._pointsBuilderList[i];
                    isHighlight ? pointsBuilder.highlight(data, dataIdx) : pointsBuilder.downplay(data, dataIdx);
                }
            }, this);
        }
        else {
            // PENDING, OPTIMIZE
            data.each(function (dataIdx) {
                for (var i = 0; i < this._pointsBuilderList.length; i++) {
                    var pointsBuilder = this._pointsBuilderList[i];
                    isHighlight ? pointsBuilder.highlight(data, dataIdx) : pointsBuilder.downplay(data, dataIdx);
                }
            });
        }
    },

    dispose: function () {
        this._pointsBuilderList.forEach(function (pointsBuilder) {
            pointsBuilder.dispose();
        });
        this.groupGL.removeAll();
    },

    remove: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/scatter3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function scatter3D_install_install(registers) {
    registers.registerChartView(Scatter3DView);
    registers.registerSeriesModel(Scatter3DSeries);

    registers.registerLayout({
        seriesType: 'scatter3D',
        reset: function (seriesModel) {
            var coordSys = seriesModel.coordinateSystem;

            if (coordSys) {
                var coordDims = coordSys.dimensions;
                if (coordDims.length < 3) {
                    if (true) {
                        console.error('scatter3D needs 3D coordinateSystem');
                    }
                    return;
                }
                var dims = coordDims.map(function (coordDim) {
                    return seriesModel.coordDimToDataDim(coordDim)[0];
                });

                var item = [];
                var out = [];

                return {
                    progress: function (params, data) {
                        var points = new Float32Array((params.end - params.start) * 3);
                        for (var idx = params.start; idx < params.end; idx++) {
                            var idx3 = (idx - params.start) * 3;
                            item[0] = data.get(dims[0], idx);
                            item[1] = data.get(dims[1], idx);
                            item[2] = data.get(dims[2], idx);
                            coordSys.dataToPoint(item, out);
                            points[idx3] = out[0];
                            points[idx3 + 1] = out[1];
                            points[idx3 + 2] = out[2];
                        }
                        data.setLayout('points', points);
                    }
                };
            }
        }
    });
}
;// CONCATENATED MODULE: ./src/chart/scatter3D.js


(0,external_echarts_.use)(scatter3D_install_install);
;// CONCATENATED MODULE: ./src/chart/lines3D/lines3DLayout.js


var lines3DLayout_vec3 = dep_glmatrix.vec3;
var lines3DLayout_vec2 = dep_glmatrix.vec2;
var lines3DLayout_normalize = lines3DLayout_vec3.normalize;
var cross = lines3DLayout_vec3.cross;
var lines3DLayout_sub = lines3DLayout_vec3.sub;
var lines3DLayout_add = lines3DLayout_vec3.add;
var lines3DLayout_create = lines3DLayout_vec3.create;

var normal = lines3DLayout_create();
var tangent = lines3DLayout_create();
var bitangent = lines3DLayout_create();
var halfVector = lines3DLayout_create();

var coord0 = [];
var coord1 = [];

function getCubicPointsOnGlobe(coords, coordSys) {
    lines3DLayout_vec2.copy(coord0, coords[0]);
    lines3DLayout_vec2.copy(coord1, coords[1]);

    var pts = [];
    var p0 = pts[0] = lines3DLayout_create();
    var p1 = pts[1] = lines3DLayout_create();
    var p2 = pts[2] = lines3DLayout_create();
    var p3 = pts[3] = lines3DLayout_create();
    coordSys.dataToPoint(coord0, p0);
    coordSys.dataToPoint(coord1, p3);
    // Get p1
    lines3DLayout_normalize(normal, p0);
    // TODO p0-p3 is parallel with normal
    lines3DLayout_sub(tangent, p3, p0);
    lines3DLayout_normalize(tangent, tangent);
    cross(bitangent, tangent, normal);
    lines3DLayout_normalize(bitangent, bitangent);
    cross(tangent, normal, bitangent);
    // p1 is half vector of p0 and tangent on p0
    lines3DLayout_add(p1, normal, tangent);
    lines3DLayout_normalize(p1, p1);

    // Get p2
    lines3DLayout_normalize(normal, p3);
    lines3DLayout_sub(tangent, p0, p3);
    lines3DLayout_normalize(tangent, tangent);
    cross(bitangent, tangent, normal);
    lines3DLayout_normalize(bitangent, bitangent);
    cross(tangent, normal, bitangent);
    // p2 is half vector of p3 and tangent on p3
    lines3DLayout_add(p2, normal, tangent);
    lines3DLayout_normalize(p2, p2);

    // Project distance of p0 on halfVector
    lines3DLayout_add(halfVector, p0, p3);
    lines3DLayout_normalize(halfVector, halfVector);
    var projDist = lines3DLayout_vec3.dot(p0, halfVector);
    // Angle of halfVector and p1
    var cosTheta = lines3DLayout_vec3.dot(halfVector, p1);

    var len = (Math.max(lines3DLayout_vec3.len(p0), lines3DLayout_vec3.len(p3)) - projDist) / cosTheta * 2;

    lines3DLayout_vec3.scaleAndAdd(p1, p0, p1, len);
    lines3DLayout_vec3.scaleAndAdd(p2, p3, p2, len);

    return pts;
}

function getCubicPointsOnPlane(coords, coordSys, up) {
    var pts = [];
    var p0 = pts[0] = lines3DLayout_vec3.create();
    var p1 = pts[1] = lines3DLayout_vec3.create();
    var p2 = pts[2] = lines3DLayout_vec3.create();
    var p3 = pts[3] = lines3DLayout_vec3.create();

    coordSys.dataToPoint(coords[0], p0);
    coordSys.dataToPoint(coords[1], p3);

    var len = lines3DLayout_vec3.dist(p0, p3);
    lines3DLayout_vec3.lerp(p1, p0, p3, 0.3);
    lines3DLayout_vec3.lerp(p2, p0, p3, 0.3);

    lines3DLayout_vec3.scaleAndAdd(p1, p1, up, Math.min(len * 0.1, 10));
    lines3DLayout_vec3.scaleAndAdd(p2, p2, up, Math.min(len * 0.1, 10));

    return pts;
}

function getPolylinePoints(coords, coordSys) {
    var pts = new Float32Array(coords.length * 3);
    var off = 0;
    var pt = [];
    for (var i = 0; i < coords.length; i++) {
        coordSys.dataToPoint(coords[i], pt);
        pts[off++] = pt[0];
        pts[off++] = pt[1];
        pts[off++] = pt[2];
    }
    return pts;
}

function prepareCoords(data) {
    var coordsList = [];

    data.each(function (idx) {
        var itemModel = data.getItemModel(idx);
        var coords = (itemModel.option instanceof Array) ?
            itemModel.option : itemModel.getShallow('coords', true);

        if (true) {
            if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) {
                throw new Error('Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.');
            }
        }
        coordsList.push(coords);
    });

    return {
        coordsList: coordsList
    };
}

function layoutGlobe(seriesModel, coordSys) {
    var data = seriesModel.getData();
    var isPolyline = seriesModel.get('polyline');

    data.setLayout('lineType', isPolyline ? 'polyline' : 'cubicBezier');

    var res = prepareCoords(data);

    data.each(function (idx) {
        var coords = res.coordsList[idx];
        var getPointsMethod = isPolyline ? getPolylinePoints : getCubicPointsOnGlobe;
        data.setItemLayout(idx, getPointsMethod(coords, coordSys));
    });
}

function layoutOnPlane(seriesModel, coordSys, normal) {
    var data = seriesModel.getData();
    var isPolyline = seriesModel.get('polyline');

    var res = prepareCoords(data);

    data.setLayout('lineType', isPolyline ? 'polyline' : 'cubicBezier');

    data.each(function (idx) {
        var coords = res.coordsList[idx];
        var pts = isPolyline ? getPolylinePoints(coords, coordSys)
            : getCubicPointsOnPlane(coords, coordSys, normal);
        data.setItemLayout(idx, pts);
    });
}

function lines3DLayout(ecModel, api) {
    ecModel.eachSeriesByType('lines3D', function (seriesModel) {
        var coordSys = seriesModel.coordinateSystem;
        if (coordSys.type === 'globe') {
            layoutGlobe(seriesModel, coordSys);
        }
        else if (coordSys.type === 'geo3D') {
            layoutOnPlane(seriesModel, coordSys, [0, 1, 0]);
        }
        else if (coordSys.type === 'mapbox3D' || coordSys.type === 'maptalks3D') {
            layoutOnPlane(seriesModel, coordSys, [0, 0, 1]);
        }
    });
};
;// CONCATENATED MODULE: ./src/chart/lines3D/Lines3DSeries.js


/* harmony default export */ const Lines3DSeries = (external_echarts_.SeriesModel.extend({

    type: 'series.lines3D',

    dependencies: ['globe'],

    visualStyleAccessPath: 'lineStyle',
    visualDrawType: 'stroke',

    getInitialData: function (option, ecModel) {
        var lineData = new external_echarts_.List(['value'], this);
        lineData.hasItemOption = false;
        lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {
            // dataItem is simply coords
            if (dataItem instanceof Array) {
                return NaN;
            }
            else {
                lineData.hasItemOption = true;
                var value = dataItem.value;
                if (value != null) {
                    return value instanceof Array ? value[dimIndex] : value;
                }
            }
        });

        return lineData;
    },

    defaultOption: {

        coordinateSystem: 'globe',

        globeIndex: 0,

        geo3DIndex: 0,

        zlevel: -10,

        polyline: false,

        effect: {
            show: false,
            period: 4,
            // Trail width
            trailWidth: 4,
            trailLength: 0.2,

            spotIntensity: 6
        },

        silent: true,

        // Support source-over, lighter
        blendMode: 'source-over',

        lineStyle: {
            width: 1,
            opacity: 0.5
            // color
        }
    }
}));
;// CONCATENATED MODULE: ./src/chart/lines3D/shader/trail2.glsl.js
/* harmony default export */ const trail2_glsl = ("@export ecgl.trail2.vertex\nattribute vec3 position: POSITION;\nattribute vec3 positionPrev;\nattribute vec3 positionNext;\nattribute float offset;\nattribute float dist;\nattribute float distAll;\nattribute float start;\n\nattribute vec4 a_Color : COLOR;\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec4 viewport : VIEWPORT;\nuniform float near : NEAR;\n\nuniform float speed : 0;\nuniform float trailLength: 0.3;\nuniform float time;\nuniform float period: 1000;\n\nuniform float spotSize: 1;\n\nvarying vec4 v_Color;\nvarying float v_Percent;\nvarying float v_SpotPercent;\n\n@import ecgl.common.wireframe.vertexHeader\n\n@import ecgl.lines3D.clipNear\n\nvoid main()\n{\n @import ecgl.lines3D.expandLine\n\n gl_Position = currProj;\n\n v_Color = a_Color;\n\n @import ecgl.common.wireframe.vertexMain\n\n#ifdef CONSTANT_SPEED\n float t = mod((speed * time + start) / distAll, 1. + trailLength) - trailLength;\n#else\n float t = mod((time + start) / period, 1. + trailLength) - trailLength;\n#endif\n\n float trailLen = distAll * trailLength;\n\n v_Percent = (dist - t * distAll) / trailLen;\n\n v_SpotPercent = spotSize / distAll;\n\n }\n@end\n\n\n@export ecgl.trail2.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float spotIntensity: 5;\n\nvarying vec4 v_Color;\nvarying float v_Percent;\nvarying float v_SpotPercent;\n\n@import ecgl.common.wireframe.fragmentHeader\n\n@import clay.util.srgb\n\nvoid main()\n{\n if (v_Percent > 1.0 || v_Percent < 0.0) {\n discard;\n }\n\n float fade = v_Percent;\n\n#ifdef SRGB_DECODE\n gl_FragColor = sRGBToLinear(color * v_Color);\n#else\n gl_FragColor = color * v_Color;\n#endif\n\n @import ecgl.common.wireframe.fragmentMain\n\n if (v_Percent > (1.0 - v_SpotPercent)) {\n gl_FragColor.rgb *= spotIntensity;\n }\n\n gl_FragColor.a *= fade;\n}\n\n@end");

;// CONCATENATED MODULE: ./src/chart/lines3D/TrailMesh2.js








var TrailMesh2_vec3 = dep_glmatrix.vec3;

function sign(a) {
    return a > 0 ? 1 : -1;
}

util_graphicGL.Shader.import(trail2_glsl);

/* harmony default export */ const TrailMesh2 = (util_graphicGL.Mesh.extend(function () {

    var material = new util_graphicGL.Material({
        shader: new util_graphicGL.Shader(
            util_graphicGL.Shader.source('ecgl.trail2.vertex'),
            util_graphicGL.Shader.source('ecgl.trail2.fragment')
        ),
        transparent: true,
        depthMask: false
    });

    var geometry = new Lines3D({
        dynamic: true
    });
    geometry.createAttribute('dist', 'float', 1);
    geometry.createAttribute('distAll', 'float', 1);
    geometry.createAttribute('start', 'float', 1);

    return {
        geometry: geometry,
        material: material,
        culling: false,
        $ignorePicking: true
    };
}, {

    updateData: function (data, api, lines3DGeometry) {
        var seriesModel = data.hostModel;
        var geometry = this.geometry;

        var effectModel = seriesModel.getModel('effect');
        var size = effectModel.get('trailWidth') * api.getDevicePixelRatio();
        var trailLength = effectModel.get('trailLength');

        var speed = seriesModel.get('effect.constantSpeed');
        var period = seriesModel.get('effect.period') * 1000;
        var useConstantSpeed = speed != null;

        if (true) {
            if (!this.getScene()) {
                console.error('TrailMesh must been add to scene before updateData');
            }
        }

        useConstantSpeed
            ? this.material.set('speed', speed / 1000)
            : this.material.set('period', period);

        this.material[useConstantSpeed ? 'define' : 'undefine']('vertex', 'CONSTANT_SPEED');

        var isPolyline = seriesModel.get('polyline');

        geometry.trailLength = trailLength;
        this.material.set('trailLength', trailLength);

        geometry.resetOffset();

        ['position', 'positionPrev', 'positionNext'].forEach(function (attrName) {
            geometry.attributes[attrName].value = lines3DGeometry.attributes[attrName].value;
        });

        var extraAttrs = ['dist', 'distAll', 'start', 'offset', 'color'];

        extraAttrs.forEach(function (attrName) {
            geometry.attributes[attrName].init(geometry.vertexCount);
        });
        geometry.indices = lines3DGeometry.indices;

        var colorArr = [];
        var effectColor = effectModel.get('trailColor');
        var effectOpacity = effectModel.get('trailOpacity');
        var hasEffectColor = effectColor != null;
        var hasEffectOpacity = effectOpacity != null;

        this.updateWorldTransform();
        var xScale = this.worldTransform.x.len();
        var yScale = this.worldTransform.y.len();
        var zScale = this.worldTransform.z.len();

        var vertexOffset = 0;

        var maxDistance = 0;

        data.each(function (idx) {
            var pts = data.getItemLayout(idx);
            var opacity = hasEffectOpacity ? effectOpacity : getItemVisualOpacity(data, idx);
            var color = getItemVisualColor(data, idx);

            if (opacity == null) {
                opacity = 1;
            }
            colorArr = util_graphicGL.parseColor(hasEffectColor ? effectColor : color, colorArr);
            colorArr[3] *= opacity;

            var vertexCount = isPolyline
                ? lines3DGeometry.getPolylineVertexCount(pts)
                : lines3DGeometry.getCubicCurveVertexCount(pts[0], pts[1], pts[2], pts[3])

            var dist = 0;
            var pos = [];
            var posPrev = [];
            for (var i = vertexOffset; i < vertexOffset + vertexCount; i++) {
                geometry.attributes.position.get(i, pos);
                pos[0] *= xScale;
                pos[1] *= yScale;
                pos[2] *= zScale;
                if (i > vertexOffset) {
                    dist += TrailMesh2_vec3.dist(pos, posPrev);
                }
                geometry.attributes.dist.set(i, dist);
                TrailMesh2_vec3.copy(posPrev, pos);
            }

            maxDistance = Math.max(maxDistance, dist);

            var randomStart = Math.random() * (useConstantSpeed ? dist : period);
            for (var i = vertexOffset; i < vertexOffset + vertexCount; i++) {
                geometry.attributes.distAll.set(i, dist);
                geometry.attributes.start.set(i, randomStart);

                geometry.attributes.offset.set(
                    i, sign(lines3DGeometry.attributes.offset.get(i)) * size / 2
                );
                geometry.attributes.color.set(i, colorArr);
            }

            vertexOffset += vertexCount;
        });

        this.material.set('spotSize', maxDistance * 0.1 * trailLength);
        this.material.set('spotIntensity', effectModel.get('spotIntensity'));

        geometry.dirty();
    },

    setAnimationTime: function (time) {
        this.material.set('time', time);
    }
}));
;// CONCATENATED MODULE: ./src/chart/lines3D/Lines3DView.js



// import TrailMesh from './TrailMesh';




util_graphicGL.Shader.import(lines3D_glsl);

function getCoordSysSize(coordSys) {
    if (coordSys.radius != null) {
        return coordSys.radius;
    }
    if (coordSys.size != null) {
        return Math.max(coordSys.size[0], coordSys.size[1], coordSys.size[2]);
    }
    else {
        return 100;
    }
}

/* harmony default export */ const Lines3DView = (external_echarts_.ChartView.extend({

    type: 'lines3D',

    __ecgl__: true,

    init: function (ecModel, api) {
        this.groupGL = new util_graphicGL.Node();

        this._meshLinesMaterial = new util_graphicGL.Material({
            shader: util_graphicGL.createShader('ecgl.meshLines3D'),
            transparent: true,
            depthMask: false
        });
        this._linesMesh = new util_graphicGL.Mesh({
            geometry: new Lines3D(),
            material: this._meshLinesMaterial,
            $ignorePicking: true
        });

        // this._trailMesh = new TrailMesh();
        this._trailMesh = new TrailMesh2();
    },

    render: function (seriesModel, ecModel, api) {

        this.groupGL.add(this._linesMesh);

        var coordSys = seriesModel.coordinateSystem;
        var data = seriesModel.getData();

        if (coordSys && coordSys.viewGL) {
            var viewGL = coordSys.viewGL;
            viewGL.add(this.groupGL);

            this._updateLines(seriesModel, ecModel, api);

            var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
            this._linesMesh.material[methodName]('fragment', 'SRGB_DECODE');
            this._trailMesh.material[methodName]('fragment', 'SRGB_DECODE');
        }

        var trailMesh = this._trailMesh;
        trailMesh.stopAnimation();

        if (seriesModel.get('effect.show')) {
            this.groupGL.add(trailMesh);

            trailMesh.updateData(data, api, this._linesMesh.geometry);

            trailMesh.__time = trailMesh.__time || 0;
            var time = 3600 * 1000; // 1hour
            this._curveEffectsAnimator = trailMesh.animate('', { loop: true })
                .when(time, {
                    __time: time
                })
                .during(function () {
                    trailMesh.setAnimationTime(trailMesh.__time);
                })
                .start();
        }
        else {
            this.groupGL.remove(trailMesh);
            this._curveEffectsAnimator = null;
        }

        this._linesMesh.material.blend = this._trailMesh.material.blend
            = seriesModel.get('blendMode') === 'lighter'
            ? util_graphicGL.additiveBlend : null;
    },

    pauseEffect: function () {
        if (this._curveEffectsAnimator) {
            this._curveEffectsAnimator.pause();
        }
    },

    resumeEffect: function () {
        if (this._curveEffectsAnimator) {
            this._curveEffectsAnimator.resume();
        }
    },

    toggleEffect: function () {
        var animator = this._curveEffectsAnimator;
        if (animator) {
            animator.isPaused() ? animator.resume() : animator.pause();
        }
    },

    _updateLines: function (seriesModel, ecModel, api) {
        var data = seriesModel.getData();
        var coordSys = seriesModel.coordinateSystem;
        var geometry = this._linesMesh.geometry;
        var isPolyline = seriesModel.get('polyline');

        geometry.expandLine = true;

        var size = getCoordSysSize(coordSys);
        geometry.segmentScale = size / 20;

        var lineWidthQueryPath = 'lineStyle.width'.split('.');
        var dpr = api.getDevicePixelRatio();
        var maxLineWidth = 0;
        data.each(function (idx) {
            var itemModel = data.getItemModel(idx);
            var lineWidth = itemModel.get(lineWidthQueryPath);
            if (lineWidth == null) {
                lineWidth = 1;
            }
            data.setItemVisual(idx, 'lineWidth', lineWidth);
            maxLineWidth = Math.max(lineWidth, maxLineWidth);
        });

        // Must set useNativeLine before calling any other methods
        geometry.useNativeLine = false;

        var nVertex = 0;
        var nTriangle = 0;
        data.each(function (idx) {
            var pts = data.getItemLayout(idx);
            if (isPolyline) {
                nVertex += geometry.getPolylineVertexCount(pts);
                nTriangle += geometry.getPolylineTriangleCount(pts);
            }
            else {
                nVertex += geometry.getCubicCurveVertexCount(pts[0], pts[1], pts[2], pts[3]);
                nTriangle += geometry.getCubicCurveTriangleCount(pts[0], pts[1], pts[2], pts[3]);
            }
        });

        geometry.setVertexCount(nVertex);
        geometry.setTriangleCount(nTriangle);
        geometry.resetOffset();

        var colorArr = [];
        data.each(function (idx) {
            var pts = data.getItemLayout(idx);
            var color = getItemVisualColor(data, idx);
            var opacity = getItemVisualOpacity(data, idx);
            var lineWidth = data.getItemVisual(idx, 'lineWidth') * dpr;
            if (opacity == null) {
                opacity = 1;
            }

            colorArr = util_graphicGL.parseColor(color, colorArr);
            colorArr[3] *= opacity;
            if (isPolyline) {
                geometry.addPolyline(pts, colorArr, lineWidth);
            }
            else {
                geometry.addCubicCurve(pts[0], pts[1], pts[2], pts[3], colorArr, lineWidth);
            }
        });

        geometry.dirty();
    },

    remove: function () {
        this.groupGL.removeAll();
    },

    dispose: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/lines3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.






function lines3D_install_install(registers) {
    registers.registerChartView(Lines3DView);
    registers.registerSeriesModel(Lines3DSeries);

    registers.registerLayout(lines3DLayout);

    registers.registerAction({
        type: 'lines3DPauseEffect',
        event: 'lines3deffectpaused',
        update: 'series.lines3D:pauseEffect'
    }, function () {});

    registers.registerAction({
        type: 'lines3DResumeEffect',
        event: 'lines3deffectresumed',
        update: 'series.lines3D:resumeEffect'
    }, function () {});

    registers.registerAction({
        type: 'lines3DToggleEffect',
        event: 'lines3deffectchanged',
        update: 'series.lines3D:toggleEffect'
    }, function () {});
}
;// CONCATENATED MODULE: ./src/chart/lines3D.js


(0,external_echarts_.use)(lines3D_install_install);
;// CONCATENATED MODULE: ./src/chart/polygons3D/Polygons3DSeries.js



function transformPolygon(coordSys, poly) {
    var ret = [];
    for (var i = 0; i < poly.length; i++) {
        ret.push(coordSys.dataToPoint(poly[i]));
    }
    return ret;
}

var Polygons3DSeries = external_echarts_.SeriesModel.extend({

    type: 'series.polygons3D',

    getRegionModel: function (idx) {
        return this.getData().getItemModel(idx);
    },

    getRegionPolygonCoords: function (idx) {
        var coordSys = this.coordinateSystem;
        var itemModel = this.getData().getItemModel(idx);
        var coords = itemModel.option instanceof Array
            ? itemModel.option : itemModel.getShallow('coords');
        if (!itemModel.get('multiPolygon')) {
            coords = [coords];
        }
        // TODO Validate
        var out = [];
        for (var i = 0; i < coords.length; i++) {
            // TODO Convert here ?
            var interiors = [];
            for (var k = 1; k < coords[i].length; k++) {
                interiors.push(transformPolygon(coordSys, coords[i][k]));
            }
            out.push({
                exterior: transformPolygon(coordSys, coords[i][0]),
                interiors: interiors
            });
        }
        return out;
    },

    getInitialData: function (option) {
        var polygonsData = new external_echarts_.List(['value'], this);
        polygonsData.hasItemOption = false;
        polygonsData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {
            // dataItem is simply coords
            if (dataItem instanceof Array) {
                return NaN;
            }
            else {
                polygonsData.hasItemOption = true;
                var value = dataItem.value;
                if (value != null) {
                    return value instanceof Array ? value[dimIndex] : value;
                }
            }
        });

        return polygonsData;
    },

    defaultOption: {

        show: true,

        data: null,

        multiPolygon: false,

        progressiveThreshold: 1e3,
        progressive: 1e3,

        zlevel: -10,

        label: {
            show: false,
            // Distance in 3d space.
            distance: 2,

            textStyle: {
                fontSize: 20,
                color: '#000',
                backgroundColor: 'rgba(255,255,255,0.7)',
                padding: 3,
                borderRadius: 4
            }
        },

        itemStyle: {
            color: '#fff',
            borderWidth: 0,
            borderColor: '#333'
        },

        emphasis: {
            itemStyle: {
                color: '#639fc0'
            },
            label: {
                show: true
            }
        }
    }
});

external_echarts_.util.merge(Polygons3DSeries.prototype, componentShadingMixin);

/* harmony default export */ const polygons3D_Polygons3DSeries = (Polygons3DSeries);
;// CONCATENATED MODULE: ./src/chart/polygons3D/Polygons3DView.js




/* harmony default export */ const Polygons3DView = (external_echarts_.ChartView.extend({

    type: 'polygons3D',

    __ecgl__: true,

    init: function (ecModel, api) {
        this.groupGL = new util_graphicGL.Node();

        this._geo3DBuilderList = [];

        this._currentStep = 0;
    },

    render: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();

        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
        }

        var geo3DBuilder = this._geo3DBuilderList[0];
        if (!geo3DBuilder) {
            geo3DBuilder = new common_Geo3DBuilder(api);
            geo3DBuilder.extrudeY = coordSys.type !== 'mapbox3D'
                && coordSys.type !== 'maptalks3D';
            this._geo3DBuilderList[0] = geo3DBuilder;
        }
        this._updateShaderDefines(coordSys, geo3DBuilder);

        geo3DBuilder.update(seriesModel, ecModel, api);
        this._geo3DBuilderList.length = 1;

        this.groupGL.add(geo3DBuilder.rootNode);
    },

    incrementalPrepareRender: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();

        var coordSys = seriesModel.coordinateSystem;
        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
        }

        this._currentStep = 0;
    },

    incrementalRender: function (params, seriesModel, ecModel, api) {
        var geo3DBuilder = this._geo3DBuilderList[this._currentStep];
        var coordSys = seriesModel.coordinateSystem;
        if (!geo3DBuilder) {
            geo3DBuilder = new common_Geo3DBuilder(api);
            geo3DBuilder.extrudeY = coordSys.type !== 'mapbox3D'
                && coordSys.type !== 'maptalks3D';
            this._geo3DBuilderList[this._currentStep] = geo3DBuilder;
        }
        geo3DBuilder.update(seriesModel, ecModel, api, params.start, params.end);
        this.groupGL.add(geo3DBuilder.rootNode);

        this._updateShaderDefines(coordSys, geo3DBuilder);

        this._currentStep++;
    },

    _updateShaderDefines: function (coordSys, geo3DBuilder) {
        var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
        geo3DBuilder.rootNode.traverse(function (mesh) {
            if (mesh.material) {
                mesh.material[methodName]('fragment', 'SRGB_DECODE');

                // FIXME
                if (coordSys.type === 'mapbox3D' || coordSys.type === 'maptalks3D') {
                    mesh.material.define('fragment', 'NORMAL_UP_AXIS', 2);
                    mesh.material.define('fragment', 'NORMAL_FRONT_AXIS', 1);
                }
            }
        });
    },

    remove: function () {
        this.groupGL.removeAll();
    },

    dispose: function () {
        this.groupGL.removeAll();
        this._geo3DBuilderList.forEach(function (geo3DBuilder) {
            geo3DBuilder.dispose();
        })
    }
}));
;// CONCATENATED MODULE: ./src/chart/polygons3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function polygons3D_install_install(registers) {
    registers.registerChartView(Polygons3DView);
    registers.registerSeriesModel(polygons3D_Polygons3DSeries);
}
;// CONCATENATED MODULE: ./src/chart/polygons3D.js


(0,external_echarts_.use)(polygons3D_install_install);
;// CONCATENATED MODULE: ./src/chart/surface/SurfaceSeries.js





var SurfaceSeries = external_echarts_.SeriesModel.extend({

    type: 'series.surface',

    dependencies: ['globe', 'grid3D', 'geo3D'],

    visualStyleAccessPath: 'itemStyle',

    formatTooltip: function (dataIndex) {
        return formatTooltip(this, dataIndex);
    },

    getInitialData: function (option, ecModel) {
        var data = option.data;

        function validateDimension(dimOpts) {
            return !(isNaN(dimOpts.min) || isNaN(dimOpts.max) || isNaN(dimOpts.step));
        }

        function getPrecision(dimOpts) {
            var getPrecision = external_echarts_.number.getPrecisionSafe;
            return Math.max(
                getPrecision(dimOpts.min), getPrecision(dimOpts.max), getPrecision(dimOpts.step)
            ) + 1;
        }

        if (!data) {
            if (!option.parametric) {
                // From surface equation
                var equation = option.equation || {};
                var xOpts = equation.x || {};
                var yOpts = equation.y || {};

                ['x', 'y'].forEach(function (dim) {
                    if (!validateDimension(equation[dim])) {
                        if (true) {
                            console.error('Invalid equation.%s', dim);
                        }
                        return;
                    }
                });
                if (typeof equation.z !== 'function') {
                    if (true) {
                        console.error('equation.z needs to be function');
                    }
                    return;
                }
                var xCount = Math.floor((xOpts.max + xOpts.step - xOpts.min) / xOpts.step);
                var yCount = Math.floor((yOpts.max + yOpts.step - yOpts.min) / yOpts.step);
                data = new Float32Array(xCount * yCount * 3);

                var xPrecision = getPrecision(xOpts);
                var yPrecision = getPrecision(yOpts);

                var off = 0;
                for (var j = 0; j < yCount; j++) {
                    for (var i = 0; i < xCount; i++) {
                        var x = i * xOpts.step + xOpts.min;
                        var y = j * yOpts.step + yOpts.min;
                        var x2 = external_echarts_.number.round(Math.min(x, xOpts.max), xPrecision);
                        var y2 = external_echarts_.number.round(Math.min(y, yOpts.max), yPrecision);
                        var z = equation.z(x2, y2);
                        data[off++] = x2;
                        data[off++] = y2;
                        data[off++] = z;
                    }
                }
            }
            else {
                var parametricEquation = option.parametricEquation || {};
                var uOpts = parametricEquation.u || {};
                var vOpts = parametricEquation.v || {};

                ['u', 'v'].forEach(function (dim) {
                    if (!validateDimension(parametricEquation[dim])) {
                        if (true) {
                            console.error('Invalid parametricEquation.%s', dim);
                        }
                        return;
                    }
                });
                ['x', 'y', 'z'].forEach(function (dim) {
                    if (typeof parametricEquation[dim] !== 'function') {
                        if (true) {
                            console.error('parametricEquation.%s needs to be function', dim);
                        }
                        return;
                    }
                });

                var uCount = Math.floor((uOpts.max + uOpts.step - uOpts.min) / uOpts.step);
                var vCount = Math.floor((vOpts.max + vOpts.step - vOpts.min) / vOpts.step);
                data = new Float32Array(uCount * vCount * 5);


                var uPrecision = getPrecision(uOpts);
                var vPrecision = getPrecision(vOpts);
                var off = 0;
                for (var j = 0; j < vCount; j++) {
                    for (var i = 0; i < uCount; i++) {
                        var u = i * uOpts.step + uOpts.min;
                        var v = j * vOpts.step + vOpts.min;
                        var u2 = external_echarts_.number.round(Math.min(u, uOpts.max), uPrecision);
                        var v2 = external_echarts_.number.round(Math.min(v, vOpts.max), vPrecision);
                        var x = parametricEquation.x(u2, v2);
                        var y = parametricEquation.y(u2, v2);
                        var z = parametricEquation.z(u2, v2);
                        data[off++] = x;
                        data[off++] = y;
                        data[off++] = z;
                        data[off++] = u2;
                        data[off++] = v2;
                    }
                }
            }
        }

        var dims = ['x', 'y', 'z'];
        if (option.parametric) {
            dims.push('u', 'v');
        }
        // PENDING getSource?
        var list = createList(this, dims, data);
        return list;
    },

    defaultOption: {
        coordinateSystem: 'cartesian3D',
        zlevel: -10,

        // Cartesian coordinate system
        grid3DIndex: 0,

        // Surface needs lambert shading to show the difference
        shading: 'lambert',

        // If parametric surface
        parametric: false,

        wireframe: {
            show: true,

            lineStyle: {
                color: 'rgba(0,0,0,0.5)',
                width: 1
            }
        },
        /**
         * Generate surface data from z = f(x, y) equation
         */
        equation: {
            // [min, max, step]
            x: {
                min: -1,
                max: 1,
                step: 0.1
            },
            y: {
                min: -1,
                max: 1,
                step: 0.1
            },
            z: null
        },

        parametricEquation: {
            // [min, max, step]
            u: {
                min: -1,
                max: 1,
                step: 0.1
            },
            v: {
                min: -1,
                max: 1,
                step: 0.1
            },
            // [x, y, z] = f(x, y)
            x: null,
            y: null,
            z: null
        },

        // Shape of give data
        // It is an array to specify rows and columns.
        // For example [30, 30]
        dataShape: null,

        itemStyle: {
            // Color
        },

        animationDurationUpdate: 500
    }
});

external_echarts_.util.merge(SurfaceSeries.prototype, componentShadingMixin);

/* harmony default export */ const surface_SurfaceSeries = (SurfaceSeries);
;// CONCATENATED MODULE: ./src/chart/surface/SurfaceView.js






var SurfaceView_vec3 = dep_glmatrix.vec3;

function isPointsNaN(pt) {
    return isNaN(pt[0]) || isNaN(pt[1]) || isNaN(pt[2]);
}

/* harmony default export */ const SurfaceView = (external_echarts_.ChartView.extend({

    type: 'surface',

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();
    },

    render: function (seriesModel, ecModel, api) {
        // Swap surfaceMesh
        var tmp = this._prevSurfaceMesh;
        this._prevSurfaceMesh = this._surfaceMesh;
        this._surfaceMesh = tmp;

        if (!this._surfaceMesh) {
            this._surfaceMesh = this._createSurfaceMesh();
        }

        this.groupGL.remove(this._prevSurfaceMesh);
        this.groupGL.add(this._surfaceMesh);

        var coordSys = seriesModel.coordinateSystem;
        var shading = seriesModel.get('shading');
        var data = seriesModel.getData();

        var shadingPrefix = 'ecgl.' + shading;
        if (!this._surfaceMesh.material || this._surfaceMesh.material.shader.name !== shadingPrefix) {
            this._surfaceMesh.material = util_graphicGL.createMaterial(shadingPrefix, ['VERTEX_COLOR', 'DOUBLE_SIDED']);
        }

        util_graphicGL.setMaterialFromModel(
            shading, this._surfaceMesh.material, seriesModel, api
        );

        if (coordSys && coordSys.viewGL) {
            coordSys.viewGL.add(this.groupGL);
            var methodName = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
            this._surfaceMesh.material[methodName]('fragment', 'SRGB_DECODE');
        }

        var isParametric = seriesModel.get('parametric');

        var dataShape = seriesModel.get('dataShape');
        if (!dataShape) {
            dataShape = this._getDataShape(data, isParametric);
            if (true) {
                if (seriesModel.get('data')) {
                    console.warn('dataShape is not provided. Guess it is ', dataShape);
                }
            }
        }

        var wireframeModel = seriesModel.getModel('wireframe');
        var wireframeLineWidth = wireframeModel.get('lineStyle.width');
        var showWireframe = wireframeModel.get('show') && wireframeLineWidth > 0;
        this._updateSurfaceMesh(this._surfaceMesh, seriesModel, dataShape, showWireframe);

        var material = this._surfaceMesh.material;
        if (showWireframe) {
            material.define('WIREFRAME_QUAD');
            material.set('wireframeLineWidth', wireframeLineWidth);
            material.set('wireframeLineColor', util_graphicGL.parseColor(wireframeModel.get('lineStyle.color')));
        }
        else {
            material.undefine('WIREFRAME_QUAD');
        }

        this._initHandler(seriesModel, api);

        this._updateAnimation(seriesModel);
    },

    _updateAnimation: function (seriesModel) {
        util_graphicGL.updateVertexAnimation(
            [
                ['prevPosition', 'position'],
                ['prevNormal', 'normal']
            ],
            this._prevSurfaceMesh,
            this._surfaceMesh,
            seriesModel
        );
    },

    _createSurfaceMesh: function () {
        var mesh = new util_graphicGL.Mesh({
            geometry: new util_graphicGL.Geometry({
                dynamic: true,
                sortTriangles: true
            }),
            shadowDepthMaterial: new util_graphicGL.Material({
                shader: new util_graphicGL.Shader(util_graphicGL.Shader.source('ecgl.sm.depth.vertex'), util_graphicGL.Shader.source('ecgl.sm.depth.fragment'))
            }),
            culling: false,
            // Render after axes
            renderOrder: 10,
            // Render normal in normal pass
            renderNormal: true
        });
        mesh.geometry.createAttribute('barycentric', 'float', 4);
        mesh.geometry.createAttribute('prevPosition', 'float', 3);
        mesh.geometry.createAttribute('prevNormal', 'float', 3);

        Object.assign(mesh.geometry, trianglesSortMixin);

        return mesh;
    },

    _initHandler: function (seriesModel, api) {
        var data = seriesModel.getData();
        var surfaceMesh = this._surfaceMesh;

        var coordSys = seriesModel.coordinateSystem;

        function getNearestPointIdx(triangle, point) {
            var nearestDist = Infinity;
            var nearestIdx = -1;
            var pos = [];
            for (var i = 0; i < triangle.length; i++) {
                surfaceMesh.geometry.attributes.position.get(triangle[i], pos);
                var dist = SurfaceView_vec3.dist(point.array, pos);
                if (dist < nearestDist) {
                    nearestDist = dist;
                    nearestIdx = triangle[i];
                }
            }
            return nearestIdx;
        }

        surfaceMesh.seriesIndex = seriesModel.seriesIndex;

        var lastDataIndex = -1;

        surfaceMesh.off('mousemove');
        surfaceMesh.off('mouseout');
        surfaceMesh.on('mousemove', function (e) {
            var idx = getNearestPointIdx(e.triangle, e.point);
            if (idx >= 0) {
                var point = [];
                surfaceMesh.geometry.attributes.position.get(idx, point);
                var value = coordSys.pointToData(point);

                var minDist = Infinity;
                var dataIndex = -1;
                var item = [];
                for (var i = 0; i < data.count(); i++) {
                    item[0] = data.get('x', i);
                    item[1] = data.get('y', i);
                    item[2] = data.get('z', i);
                    var dist = SurfaceView_vec3.squaredDistance(item, value);
                    if (dist < minDist) {
                        dataIndex = i;
                        minDist = dist;
                    }
                }

                if (dataIndex !== lastDataIndex) {
                    api.dispatchAction({
                        type: 'grid3DShowAxisPointer',
                        value: value
                    });
                }

                lastDataIndex = dataIndex;
                surfaceMesh.dataIndex = dataIndex;
            }
            else {
                surfaceMesh.dataIndex = -1;
            }
        }, this);
        surfaceMesh.on('mouseout', function (e) {
            lastDataIndex = -1;
            surfaceMesh.dataIndex = -1;

            api.dispatchAction({
                type: 'grid3DHideAxisPointer'
            });
        }, this);
    },

    _updateSurfaceMesh: function (surfaceMesh, seriesModel, dataShape, showWireframe) {

        var geometry = surfaceMesh.geometry;
        var data = seriesModel.getData();
        var pointsArr = data.getLayout('points');

        var invalidDataCount = 0;
        data.each(function (idx) {
            if (!data.hasValue(idx)) {
                invalidDataCount++;
            }
        });
        var needsSplitQuad = invalidDataCount || showWireframe;

        var positionAttr = geometry.attributes.position;
        var normalAttr = geometry.attributes.normal;
        var texcoordAttr = geometry.attributes.texcoord0;
        var barycentricAttr = geometry.attributes.barycentric;
        var colorAttr = geometry.attributes.color;
        var row = dataShape[0];
        var column = dataShape[1];
        var shading = seriesModel.get('shading');
        var needsNormal = shading !== 'color';

        if (needsSplitQuad) {
            // TODO, If needs remove the invalid points, or set color transparent.
            var vertexCount = (row - 1) * (column - 1) * 4;
            positionAttr.init(vertexCount);
            if (showWireframe) {
                barycentricAttr.init(vertexCount);
            }
        }
        else {
            positionAttr.value = new Float32Array(pointsArr);
        }
        colorAttr.init(geometry.vertexCount);
        texcoordAttr.init(geometry.vertexCount);

        var quadToTriangle = [0, 3, 1, 1, 3, 2];
        // 3----2
        // 0----1
        // Make sure pixels on 1---3 edge will not have channel 0.
        // And pixels on four edges have at least one channel 0.
        var quadBarycentric = [
            [1, 1, 0, 0],
            [0, 1, 0, 1],
            [1, 0, 0, 1],
            [1, 0, 1, 0]
        ];

        var indices = geometry.indices = new (geometry.vertexCount > 0xffff ? Uint32Array : Uint16Array)((row - 1) * (column - 1) * 6);
        var getQuadIndices = function (i, j, out) {
            out[1] = i * column + j;
            out[0] = i * column + j + 1;
            out[3] = (i + 1) * column + j + 1;
            out[2] = (i + 1) * column + j;
        };

        var isTransparent = false;

        if (needsSplitQuad) {
            var quadIndices = [];
            var pos = [];
            var faceOffset = 0;

            if (needsNormal) {
                normalAttr.init(geometry.vertexCount);
            }
            else {
                normalAttr.value = null;
            }

            var pts = [[], [], []];
            var v21 = [], v32 = [];
            var normal = SurfaceView_vec3.create();

            var getFromArray = function (arr, idx, out) {
                var idx3 = idx * 3;
                out[0] = arr[idx3];
                out[1] = arr[idx3 + 1];
                out[2] = arr[idx3 + 2];
                return out;
            };
            var vertexNormals = new Float32Array(pointsArr.length);
            var vertexColors = new Float32Array(pointsArr.length / 3 * 4);

            for (var i = 0; i < data.count(); i++) {
                if (data.hasValue(i)) {
                    var rgbaArr = util_graphicGL.parseColor(getItemVisualColor(data, i));
                    var opacity = getItemVisualOpacity(data, i);
                    opacity != null && (rgbaArr[3] *= opacity);
                    if (rgbaArr[3] < 0.99) {
                        isTransparent = true;
                    }
                    for (var k = 0; k < 4; k++) {
                        vertexColors[i * 4 + k] = rgbaArr[k];
                    }
                }
            }
            var farPoints = [1e7, 1e7, 1e7];
            for (var i = 0; i < row - 1; i++) {
                for (var j = 0; j < column - 1; j++) {
                    var dataIndex = i * (column - 1) + j;
                    var vertexOffset = dataIndex * 4;

                    getQuadIndices(i, j, quadIndices);

                    var invisibleQuad = false;
                    for (var k = 0; k < 4; k++) {
                        getFromArray(pointsArr, quadIndices[k], pos);
                        if (isPointsNaN(pos)) {
                            // Quad is invisible if any point is NaN
                            invisibleQuad = true;
                        }
                    }

                    for (var k = 0; k < 4; k++) {
                        if (invisibleQuad) {
                            // Move point far away
                            positionAttr.set(vertexOffset + k, farPoints);
                        }
                        else {
                            getFromArray(pointsArr, quadIndices[k], pos);
                            positionAttr.set(vertexOffset + k, pos);
                        }
                        if (showWireframe) {
                            barycentricAttr.set(vertexOffset + k, quadBarycentric[k]);
                        }
                    }
                    for (var k = 0; k < 6; k++) {
                        indices[faceOffset++] = quadToTriangle[k] + vertexOffset;
                    }
                    // Vertex normals
                    if (needsNormal && !invisibleQuad) {
                        for (var k = 0; k < 2; k++) {
                            var k3 = k * 3;

                            for (var m = 0; m < 3; m++) {
                                var idx = quadIndices[quadToTriangle[k3] + m];
                                getFromArray(pointsArr, idx, pts[m]);
                            }

                            SurfaceView_vec3.sub(v21, pts[0], pts[1]);
                            SurfaceView_vec3.sub(v32, pts[1], pts[2]);
                            SurfaceView_vec3.cross(normal, v21, v32);
                            // Weighted by the triangle area
                            for (var m = 0; m < 3; m++) {
                                var idx3 = quadIndices[quadToTriangle[k3] + m] * 3;
                                vertexNormals[idx3] = vertexNormals[idx3] + normal[0];
                                vertexNormals[idx3 + 1] = vertexNormals[idx3 + 1] + normal[1];
                                vertexNormals[idx3 + 2] = vertexNormals[idx3 + 2] + normal[2];
                            }
                        }
                    }

                }
            }
            if (needsNormal) {
                for (var i = 0; i < vertexNormals.length / 3; i++) {
                    getFromArray(vertexNormals, i, normal);
                    SurfaceView_vec3.normalize(normal, normal);
                    vertexNormals[i * 3] = normal[0];
                    vertexNormals[i * 3 + 1] = normal[1];
                    vertexNormals[i * 3 + 2] = normal[2];
                }
            }
            // Split normal and colors, write to the attributes.
            var rgbaArr = [];
            var uvArr = [];
            for (var i = 0; i < row - 1; i++) {
                for (var j = 0; j < column - 1; j++) {
                    var dataIndex = i * (column - 1) + j;
                    var vertexOffset = dataIndex * 4;

                    getQuadIndices(i, j, quadIndices);
                    for (var k = 0; k < 4; k++) {
                        for (var m = 0; m < 4; m++) {
                            rgbaArr[m] = vertexColors[quadIndices[k] * 4 + m];
                        }
                        colorAttr.set(vertexOffset + k, rgbaArr);

                        if (needsNormal) {
                            getFromArray(vertexNormals, quadIndices[k], normal);
                            normalAttr.set(vertexOffset + k, normal);
                        }

                        var idx = quadIndices[k];
                        uvArr[0] = (idx % column) / (column - 1);
                        uvArr[1] = Math.floor(idx / column) / (row - 1);
                        texcoordAttr.set(vertexOffset + k, uvArr);
                    }
                    dataIndex++;
                }
            }
        }
        else {
            var uvArr = [];
            for (var i = 0; i < data.count(); i++) {
                uvArr[0] = (i % column) / (column - 1);
                uvArr[1] = Math.floor(i / column) / (row - 1);
                var rgbaArr = util_graphicGL.parseColor(getItemVisualColor(data, i));
                var opacity = getItemVisualOpacity(data, i);
                opacity != null && (rgbaArr[3] *= opacity);
                if (rgbaArr[3] < 0.99) {
                    isTransparent = true;
                }
                colorAttr.set(i, rgbaArr);
                texcoordAttr.set(i, uvArr);
            }
            var quadIndices = [];
            // Triangles
            var cursor = 0;
            for (var i = 0; i < row - 1; i++) {
                for (var j = 0; j < column - 1; j++) {

                    getQuadIndices(i, j, quadIndices);

                    for (var k = 0; k < 6; k++) {
                        indices[cursor++] = quadIndices[quadToTriangle[k]];
                    }
                }
            }
            if (needsNormal) {
                geometry.generateVertexNormals();
            }
            else {
                normalAttr.value = null;
            }
        }
        if (surfaceMesh.material.get('normalMap')) {
            geometry.generateTangents();
        }


        geometry.updateBoundingBox();
        geometry.dirty();

        surfaceMesh.material.transparent = isTransparent;
        surfaceMesh.material.depthMask = !isTransparent;
    },

    _getDataShape: function (data, isParametric) {

        var prevX = -Infinity;
        var rowCount = 0;
        var columnCount = 0;
        var prevColumnCount = 0;

        var mayInvalid = false;

        var rowDim = isParametric ? 'u' : 'x';
        var dataCount = data.count();
        // Check data format
        for (var i = 0; i < dataCount; i++) {
            var x = data.get(rowDim, i);
            if (x < prevX) {
                if (prevColumnCount && prevColumnCount !== columnCount) {
                    if (true) {
                        mayInvalid = true;
                    }
                }
                // A new row.
                prevColumnCount = columnCount;
                columnCount = 0;
                rowCount++;
            }
            prevX = x;
            columnCount++;
        }
        if (!rowCount || columnCount === 1) {
            mayInvalid = true;
        }
        if (!mayInvalid) {
            return [rowCount + 1, columnCount];
        }

        var rows = Math.floor(Math.sqrt(dataCount));
        while (rows > 0) {
            if (Math.floor(dataCount / rows) === dataCount / rows) { // Can be divided
                return [rows, dataCount / rows];
            }
            rows--;
        }

        // Bailout
        rows = Math.floor(Math.sqrt(dataCount));
        return [rows, rows];
    },

    dispose: function () {
        this.groupGL.removeAll();
    },

    remove: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/surface/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function surface_install_install(registers) {
    registers.registerChartView(SurfaceView);
    registers.registerSeriesModel(surface_SurfaceSeries);

    registers.registerLayout(function (ecModel, api) {
        ecModel.eachSeriesByType('surface', function (surfaceModel) {
            var cartesian = surfaceModel.coordinateSystem;
            if (!cartesian || cartesian.type !== 'cartesian3D') {
                if (true) {
                    console.error('Surface chart only support cartesian3D coordinateSystem');
                }
            }
            var data = surfaceModel.getData();
            var points = new Float32Array(3 * data.count());
            var nanPoint = [NaN, NaN, NaN];

            if (cartesian && cartesian.type === 'cartesian3D') {
                var coordDims = cartesian.dimensions;
                var dims = coordDims.map(function (coordDim) {
                    return surfaceModel.coordDimToDataDim(coordDim)[0];
                });
                data.each(dims, function (x, y, z, idx) {
                    var pt;
                    if (!data.hasValue(idx)) {
                        pt = nanPoint;
                    }
                    else {
                        pt = cartesian.dataToPoint([x, y, z]);
                    }
                    points[idx * 3] = pt[0];
                    points[idx * 3 + 1] = pt[1];
                    points[idx * 3 + 2] = pt[2];
                });
            }
            data.setLayout('points', points);
        });
    });
}
;// CONCATENATED MODULE: ./src/chart/surface.js


(0,external_echarts_.use)(surface_install_install);
;// CONCATENATED MODULE: ./src/chart/map3D/Map3DSeries.js










function Map3DSeries_transformPolygon(mapbox3DCoordSys, poly) {
    var newPoly = [];
    for (var k = 0; k < poly.length; k++) {
        newPoly.push(mapbox3DCoordSys.dataToPoint(poly[k]));
    }
    return newPoly;
}

var Map3DSeries = external_echarts_.SeriesModel.extend({

    type: 'series.map3D',

    layoutMode: 'box',

    coordinateSystem: null,

    visualStyleAccessPath: 'itemStyle',

    optionUpdated: function (newOpt) {
        newOpt = newOpt || {};
        var coordSysType = this.get('coordinateSystem');
        if (coordSysType == null || coordSysType === 'geo3D') {
            return;
        }

        if (true) {
            var propsNeedToCheck = [
                'left', 'top', 'width', 'height',
                'boxWidth', 'boxDepth', 'boxHeight',
                'light', 'viewControl', 'postEffect', 'temporalSuperSampling',
                'environment', 'groundPlane'
            ];
            var ignoredProperties = [];
            propsNeedToCheck.forEach(function (propName) {
                if (newOpt[propName] != null) {
                    ignoredProperties.push(propName);
                }
            });
            if (ignoredProperties.length) {
                console.warn(
                    'Property %s in map3D series will be ignored if coordinate system is %s',
                    ignoredProperties.join(', '), coordSysType
                );
            }
        }

        if (this.get('groundPlane.show')) {
            // Force disable groundPlane if map3D has other coordinate systems.
            this.option.groundPlane.show = false;
        }

        // Reset geo.
        this._geo = null;
    },

    getInitialData: function (option) {
        option.data = this.getFilledRegions(option.data, option.map);

        var dimensions = external_echarts_.helper.createDimensions(option.data, {
            coordDimensions: ['value']
        });
        var list = new external_echarts_.List(dimensions, this);
        list.initData(option.data);

        var regionModelMap = {};
        list.each(function (idx) {
            var name = list.getName(idx);
            var itemModel = list.getItemModel(idx);
            regionModelMap[name] = itemModel;
        });

        this._regionModelMap = regionModelMap;

        return list;
    },

    formatTooltip: function (dataIndex) {
        return formatTooltip(this, dataIndex);
    },

    getRegionModel: function (idx) {
        var name = this.getData().getName(idx);
        return this._regionModelMap[name] || new external_echarts_.Model(null, this);
    },

    getRegionPolygonCoords: function (idx) {
        var coordSys = this.coordinateSystem;
        var name = this.getData().getName(idx);
        if (coordSys.transform) {
            var region = coordSys.getRegion(name);
            return region ? region.geometries : [];
        }
        else {
            if (!this._geo) {
                this._geo = coord_geo3DCreator.createGeo3D(this);
            }
            var region = this._geo.getRegion(name);
            var ret = [];
            for (var k = 0; k < region.geometries.length; k++) {
                var geo = region.geometries[k];
                var interiors = [];
                var exterior = Map3DSeries_transformPolygon(coordSys, geo.exterior);
                if (interiors && interiors.length) {
                    for (var m = 0; m < geo.interiors.length; m++) {
                        interiors.push(Map3DSeries_transformPolygon(coordSys, interiors[m]));
                    }
                }
                ret.push({
                    interiors: interiors,
                    exterior: exterior
                });
            }
            return ret;
        }
    },

    /**
     * Format label
     * @param {string} name Region name
     * @param {string} [status='normal'] 'normal' or 'emphasis'
     * @return {string}
     */
    getFormattedLabel: function (dataIndex, status) {
        var text = util_format.getFormattedLabel(this, dataIndex, status);
        if (text == null) {
            text = this.getData().getName(dataIndex);
        }
        return text;
    },

    defaultOption: {
        // Support geo3D, mapbox, maptalks3D
        coordinateSystem: 'geo3D',
        // itemStyle: {},
        // height,
        // label: {}
        data: null
    }
});

external_echarts_.util.merge(Map3DSeries.prototype, geo3DModelMixin);

external_echarts_.util.merge(Map3DSeries.prototype, componentViewControlMixin);
external_echarts_.util.merge(Map3DSeries.prototype, componentPostEffectMixin);
external_echarts_.util.merge(Map3DSeries.prototype, componentLightMixin);
external_echarts_.util.merge(Map3DSeries.prototype, componentShadingMixin);

/* harmony default export */ const map3D_Map3DSeries = (Map3DSeries);
;// CONCATENATED MODULE: ./src/chart/map3D/Map3DView.js







/* harmony default export */ const Map3DView = (external_echarts_.ChartView.extend({

    type: 'map3D',

    __ecgl__: true,

    init: function (ecModel, api) {
        this._geo3DBuilder = new common_Geo3DBuilder(api);
        this.groupGL = new util_graphicGL.Node();
    },

    render: function (map3DModel, ecModel, api) {

        var coordSys = map3DModel.coordinateSystem;

        if (!coordSys || !coordSys.viewGL) {
            return;
        }

        this.groupGL.add(this._geo3DBuilder.rootNode);
        coordSys.viewGL.add(this.groupGL);

        var geo3D;
        if (coordSys.type === 'geo3D') {
            geo3D = coordSys;

            if (!this._sceneHelper) {
                this._sceneHelper = new common_SceneHelper();
                this._sceneHelper.initLight(this.groupGL);
            }

            this._sceneHelper.setScene(coordSys.viewGL.scene);
            this._sceneHelper.updateLight(map3DModel);

            // Set post effect
            coordSys.viewGL.setPostEffect(map3DModel.getModel('postEffect'), api);
            coordSys.viewGL.setTemporalSuperSampling(map3DModel.getModel('temporalSuperSampling'));

            var control = this._control;
            if (!control) {
                control = this._control = new util_OrbitControl({
                    zr: api.getZr()
                });
                this._control.init();
            }
            var viewControlModel = map3DModel.getModel('viewControl');
            control.setViewGL(coordSys.viewGL);
            control.setFromViewControlModel(viewControlModel, 0);

            control.off('update');
            control.on('update', function () {
                api.dispatchAction({
                    type: 'map3DChangeCamera',
                    alpha: control.getAlpha(),
                    beta: control.getBeta(),
                    distance: control.getDistance(),
                    from: this.uid,
                    map3DId: map3DModel.id
                });
            });

            this._geo3DBuilder.extrudeY = true;
        }
        else {
            if (this._control) {
                this._control.dispose();
                this._control = null;
            }
            if (this._sceneHelper) {
                this._sceneHelper.dispose();
                this._sceneHelper = null;
            }
            geo3D = map3DModel.getData().getLayout('geo3D');

            this._geo3DBuilder.extrudeY = false;
        }

        this._geo3DBuilder.update(map3DModel, ecModel, api, 0, map3DModel.getData().count());


        // Must update after geo3D.viewGL.setPostEffect to determine linear space
        var srgbDefineMethod = coordSys.viewGL.isLinearSpace() ? 'define' : 'undefine';
        this._geo3DBuilder.rootNode.traverse(function (mesh) {
            if (mesh.material) {
                mesh.material[srgbDefineMethod]('fragment', 'SRGB_DECODE');
            }
        });
    },

    afterRender: function (map3DModel, ecModel, api, layerGL) {
        var renderer = layerGL.renderer;
        var coordSys = map3DModel.coordinateSystem;
        if (coordSys && coordSys.type === 'geo3D') {
            this._sceneHelper.updateAmbientCubemap(renderer, map3DModel, api);
            this._sceneHelper.updateSkybox(renderer, map3DModel, api);
        }
    },

    dispose: function () {
        this.groupGL.removeAll();
        this._control.dispose();
        this._geo3DBuilder.dispose();
    }
}));
;// CONCATENATED MODULE: ./src/chart/map3D/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.







function map3D_install_install(registers) {
    // Depends on geo3d
    install_install(registers);

    registers.registerChartView(Map3DView);
    registers.registerSeriesModel(map3D_Map3DSeries);
    registers.registerAction({
        type: 'map3DChangeCamera',
        event: 'map3dcamerachanged',
        update: 'series:updateCamera'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'series', subType: 'map3D', query: payload
        }, function (componentModel) {
            componentModel.setView(payload);
        });
    });
}
;// CONCATENATED MODULE: ./src/chart/map3D.js


(0,external_echarts_.use)(map3D_install_install);
;// CONCATENATED MODULE: ./src/chart/scatterGL/ScatterGLSeries.js


/* harmony default export */ const ScatterGLSeries = (external_echarts_.SeriesModel.extend({

    type: 'series.scatterGL',

    dependencies: ['grid', 'polar', 'geo', 'singleAxis'],

    visualStyleAccessPath: 'itemStyle',

    hasSymbolVisual: true,

    getInitialData: function () {
        return external_echarts_.helper.createList(this);
    },

    defaultOption: {
        coordinateSystem: 'cartesian2d',
        zlevel: 10,

        progressive: 1e5,
        progressiveThreshold: 1e5,

        // Cartesian coordinate system
        // xAxisIndex: 0,
        // yAxisIndex: 0,

        // Polar coordinate system
        // polarIndex: 0,

        // Geo coordinate system
        // geoIndex: 0,

        large: false,

        symbol: 'circle',
        symbolSize: 10,

        // symbolSize scale when zooming.
        zoomScale: 0,

        // Support source-over, lighter
        blendMode: 'source-over',

        itemStyle: {
            opacity: 0.8
        },


        postEffect: {
            enable: false,
            colorCorrection: {
                exposure: 0,
                brightness: 0,
                contrast: 1,
                saturation: 1,
                enable: true
            }
        }

    }
}));
;// CONCATENATED MODULE: ./src/chart/common/GLViewHelper.js




function GLViewHelper(viewGL) {
    this.viewGL = viewGL;
}

GLViewHelper.prototype.reset = function (seriesModel, api) {
    this._updateCamera(api.getWidth(), api.getHeight(), api.getDevicePixelRatio());
    this._viewTransform = create();
    this.updateTransform(seriesModel, api);
};

GLViewHelper.prototype.updateTransform = function (seriesModel, api) {
    var coordinateSystem = seriesModel.coordinateSystem;

    if (coordinateSystem.getRoamTransform) {

        matrix_invert(this._viewTransform, coordinateSystem.getRoamTransform());

        this._setCameraTransform(this._viewTransform);

        api.getZr().refresh();
    }
};

// Reimplement the dataToPoint of coordinate system.
// Remove the effect of pan/zoom transform
GLViewHelper.prototype.dataToPoint = function (coordSys, data, pt) {
    pt = coordSys.dataToPoint(data, null, pt);
    var viewTransform = this._viewTransform;
    if (viewTransform) {
        applyTransform(pt, pt, viewTransform);
    }
};

/**
 * Remove transform info in point.
 */
GLViewHelper.prototype.removeTransformInPoint = function (pt) {
    if (this._viewTransform) {
        applyTransform(pt, pt, this._viewTransform);
    }
    return pt;
};

/**
 * Return number
 */
GLViewHelper.prototype.getZoom = function () {
    if (this._viewTransform) {
        var m = this._viewTransform;
        return 1 / Math.max(
            Math.sqrt(m[0] * m[0] + m[1] * m[1]),
            Math.sqrt(m[2] * m[2] + m[3] * m[3])
        );
    }
    return 1;
};

GLViewHelper.prototype._setCameraTransform = function (m) {
    var camera = this.viewGL.camera;
    camera.position.set(m[4], m[5], 0);
    camera.scale.set(
        Math.sqrt(m[0] * m[0] + m[1] * m[1]),
        Math.sqrt(m[2] * m[2] + m[3] * m[3]),
        1
    );
};

GLViewHelper.prototype._updateCamera = function (width, height, dpr) {
    // TODO, left, top, right, bottom
    this.viewGL.setViewport(0, 0, width, height, dpr);
    var camera = this.viewGL.camera;
    camera.left = camera.top = 0;
    camera.bottom = height;
    camera.right = width;
    camera.near = 0;
    camera.far = 100;
};

/* harmony default export */ const common_GLViewHelper = (GLViewHelper);
;// CONCATENATED MODULE: ./src/chart/scatterGL/ScatterGLView.js







/* harmony default export */ const ScatterGLView = (external_echarts_.ChartView.extend({

    type: 'scatterGL',

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();
        this.viewGL = new core_ViewGL('orthographic');

        this.viewGL.add(this.groupGL);

        this._pointsBuilderList = [];
        this._currentStep = 0;

        this._sizeScale = 1;

        this._glViewHelper = new common_GLViewHelper(this.viewGL);
    },

    render: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();
        this._glViewHelper.reset(seriesModel, api);

        if (!seriesModel.getData().count()) {
            return;
        }

        var pointsBuilder = this._pointsBuilderList[0];
        if (!pointsBuilder) {
            pointsBuilder = this._pointsBuilderList[0] = new common_PointsBuilder(true, api);
        }
        this._pointsBuilderList.length = 1;

        this.groupGL.add(pointsBuilder.rootNode);

        this._removeTransformInPoints(seriesModel.getData().getLayout('points'));
        pointsBuilder.update(seriesModel, ecModel, api);

        this.viewGL.setPostEffect(seriesModel.getModel('postEffect'), api);
    },

    incrementalPrepareRender: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();
        this._glViewHelper.reset(seriesModel, api);

        this._currentStep = 0;

        this.viewGL.setPostEffect(seriesModel.getModel('postEffect'), api);
    },

    incrementalRender: function (params, seriesModel, ecModel, api) {
        if (params.end <= params.start) {
            return;
        }

        var pointsBuilder = this._pointsBuilderList[this._currentStep];
        if (!pointsBuilder) {
            pointsBuilder = new common_PointsBuilder(true, api);
            this._pointsBuilderList[this._currentStep] = pointsBuilder;
        }
        this.groupGL.add(pointsBuilder.rootNode);

        this._removeTransformInPoints(seriesModel.getData().getLayout('points'));

        pointsBuilder.setSizeScale(this._sizeScale);
        pointsBuilder.update(seriesModel, ecModel, api, params.start, params.end);

        api.getZr().refresh();

        this._currentStep++;
    },

    updateTransform: function (seriesModel, ecModel, api) {
        if (seriesModel.coordinateSystem.getRoamTransform) {
            this._glViewHelper.updateTransform(seriesModel, api);

            var zoom = this._glViewHelper.getZoom();
            var sizeScale = Math.max((seriesModel.get('zoomScale') || 0) * (zoom - 1) + 1, 0);
            this._sizeScale = sizeScale;

            this._pointsBuilderList.forEach(function (pointsBuilder) {
                pointsBuilder.setSizeScale(sizeScale);
            });
        }
    },

    _removeTransformInPoints: function (points) {
        if (!points) {
            return;
        }
        var pt = [];
        for (var i = 0; i < points.length; i += 2) {
            pt[0] = points[i];
            pt[1] = points[i + 1];
            this._glViewHelper.removeTransformInPoint(pt);
            points[i] = pt[0];
            points[i + 1] = pt[1];
        }
    },


    dispose: function () {
        this.groupGL.removeAll();
        this._pointsBuilderList.forEach(function (pointsBuilder) {
            pointsBuilder.dispose();
        });
    },

    remove: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/scatterGL/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function scatterGL_install_install(registers) {
    registers.registerChartView(ScatterGLView);
    registers.registerSeriesModel(ScatterGLSeries);

    registers.registerLayout({
        seriesType: 'scatterGL',
        reset: function (seriesModel) {
            var coordSys = seriesModel.coordinateSystem;
            var data = seriesModel.getData();

            var progress;
            if (coordSys) {
                var dims = coordSys.dimensions.map(function (dim) {
                    return data.mapDimension(dim);
                }).slice(0, 2);
                var pt = [];
                if (dims.length === 1) {
                    progress = function (params) {
                        var points = new Float32Array((params.end - params.start) * 2);
                        for (var idx = params.start; idx < params.end; idx++) {
                            var offset = (idx - params.start) * 2;
                            var x = data.get(dims[0], idx);
                            var pt = coordSys.dataToPoint(x);
                            points[offset] = pt[0];
                            points[offset + 1] = pt[1];
                        }
                        data.setLayout('points', points);
                    };
                }
                else if (dims.length === 2) {
                    progress = function (params) {
                        var points = new Float32Array((params.end - params.start) * 2);
                        for (var idx = params.start; idx < params.end; idx++) {
                            var offset = (idx - params.start) * 2;
                            var x = data.get(dims[0], idx);
                            var y = data.get(dims[1], idx);
                            pt[0] = x;
                            pt[1] = y;

                            pt = coordSys.dataToPoint(pt);
                            points[offset] = pt[0];
                            points[offset + 1] = pt[1];
                        }
                        data.setLayout('points', points);
                    };
                }
            }

            return { progress: progress };
        }
    });
}
;// CONCATENATED MODULE: ./src/chart/scatterGL.js


(0,external_echarts_.use)(scatterGL_install_install);
;// CONCATENATED MODULE: ./node_modules/echarts/lib/data/Graph.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
 // id may be function name of Object, add a prefix to avoid this problem.

function generateNodeKey(id) {
  return '_EC_' + id;
}

var Graph_Graph =
/** @class */
function () {
  function Graph(directed) {
    this.type = 'graph';
    this.nodes = [];
    this.edges = [];
    this._nodesMap = {};
    /**
     * @type {Object.<string, module:echarts/data/Graph.Edge>}
     * @private
     */

    this._edgesMap = {};
    this._directed = directed || false;
  }
  /**
   * If is directed graph
   */


  Graph.prototype.isDirected = function () {
    return this._directed;
  };

  ;
  /**
   * Add a new node
   */

  Graph.prototype.addNode = function (id, dataIndex) {
    id = id == null ? '' + dataIndex : '' + id;
    var nodesMap = this._nodesMap;

    if (nodesMap[generateNodeKey(id)]) {
      if (true) {
        console.error('Graph nodes have duplicate name or id');
      }

      return;
    }

    var node = new GraphNode(id, dataIndex);
    node.hostGraph = this;
    this.nodes.push(node);
    nodesMap[generateNodeKey(id)] = node;
    return node;
  };

  ;
  /**
   * Get node by data index
   */

  Graph.prototype.getNodeByIndex = function (dataIndex) {
    var rawIdx = this.data.getRawIndex(dataIndex);
    return this.nodes[rawIdx];
  };

  ;
  /**
   * Get node by id
   */

  Graph.prototype.getNodeById = function (id) {
    return this._nodesMap[generateNodeKey(id)];
  };

  ;
  /**
   * Add a new edge
   */

  Graph.prototype.addEdge = function (n1, n2, dataIndex) {
    var nodesMap = this._nodesMap;
    var edgesMap = this._edgesMap; // PNEDING

    if (typeof n1 === 'number') {
      n1 = this.nodes[n1];
    }

    if (typeof n2 === 'number') {
      n2 = this.nodes[n2];
    }

    if (!(n1 instanceof GraphNode)) {
      n1 = nodesMap[generateNodeKey(n1)];
    }

    if (!(n2 instanceof GraphNode)) {
      n2 = nodesMap[generateNodeKey(n2)];
    }

    if (!n1 || !n2) {
      return;
    }

    var key = n1.id + '-' + n2.id;
    var edge = new GraphEdge(n1, n2, dataIndex);
    edge.hostGraph = this;

    if (this._directed) {
      n1.outEdges.push(edge);
      n2.inEdges.push(edge);
    }

    n1.edges.push(edge);

    if (n1 !== n2) {
      n2.edges.push(edge);
    }

    this.edges.push(edge);
    edgesMap[key] = edge;
    return edge;
  };

  ;
  /**
   * Get edge by data index
   */

  Graph.prototype.getEdgeByIndex = function (dataIndex) {
    var rawIdx = this.edgeData.getRawIndex(dataIndex);
    return this.edges[rawIdx];
  };

  ;
  /**
   * Get edge by two linked nodes
   */

  Graph.prototype.getEdge = function (n1, n2) {
    if (n1 instanceof GraphNode) {
      n1 = n1.id;
    }

    if (n2 instanceof GraphNode) {
      n2 = n2.id;
    }

    var edgesMap = this._edgesMap;

    if (this._directed) {
      return edgesMap[n1 + '-' + n2];
    } else {
      return edgesMap[n1 + '-' + n2] || edgesMap[n2 + '-' + n1];
    }
  };

  ;
  /**
   * Iterate all nodes
   */

  Graph.prototype.eachNode = function (cb, context) {
    var nodes = this.nodes;
    var len = nodes.length;

    for (var i = 0; i < len; i++) {
      if (nodes[i].dataIndex >= 0) {
        cb.call(context, nodes[i], i);
      }
    }
  };

  ;
  /**
   * Iterate all edges
   */

  Graph.prototype.eachEdge = function (cb, context) {
    var edges = this.edges;
    var len = edges.length;

    for (var i = 0; i < len; i++) {
      if (edges[i].dataIndex >= 0 && edges[i].node1.dataIndex >= 0 && edges[i].node2.dataIndex >= 0) {
        cb.call(context, edges[i], i);
      }
    }
  };

  ;
  /**
   * Breadth first traverse
   * Return true to stop traversing
   */

  Graph.prototype.breadthFirstTraverse = function (cb, startNode, direction, context) {
    if (!(startNode instanceof GraphNode)) {
      startNode = this._nodesMap[generateNodeKey(startNode)];
    }

    if (!startNode) {
      return;
    }

    var edgeType = direction === 'out' ? 'outEdges' : direction === 'in' ? 'inEdges' : 'edges';

    for (var i = 0; i < this.nodes.length; i++) {
      this.nodes[i].__visited = false;
    }

    if (cb.call(context, startNode, null)) {
      return;
    }

    var queue = [startNode];

    while (queue.length) {
      var currentNode = queue.shift();
      var edges = currentNode[edgeType];

      for (var i = 0; i < edges.length; i++) {
        var e = edges[i];
        var otherNode = e.node1 === currentNode ? e.node2 : e.node1;

        if (!otherNode.__visited) {
          if (cb.call(context, otherNode, currentNode)) {
            // Stop traversing
            return;
          }

          queue.push(otherNode);
          otherNode.__visited = true;
        }
      }
    }
  };

  ; // TODO
  // depthFirstTraverse(
  //     cb, startNode, direction, context
  // ) {
  // };
  // Filter update

  Graph.prototype.update = function () {
    var data = this.data;
    var edgeData = this.edgeData;
    var nodes = this.nodes;
    var edges = this.edges;

    for (var i = 0, len = nodes.length; i < len; i++) {
      nodes[i].dataIndex = -1;
    }

    for (var i = 0, len = data.count(); i < len; i++) {
      nodes[data.getRawIndex(i)].dataIndex = i;
    }

    edgeData.filterSelf(function (idx) {
      var edge = edges[edgeData.getRawIndex(idx)];
      return edge.node1.dataIndex >= 0 && edge.node2.dataIndex >= 0;
    }); // Update edge

    for (var i = 0, len = edges.length; i < len; i++) {
      edges[i].dataIndex = -1;
    }

    for (var i = 0, len = edgeData.count(); i < len; i++) {
      edges[edgeData.getRawIndex(i)].dataIndex = i;
    }
  };

  ;
  /**
   * @return {module:echarts/data/Graph}
   */

  Graph.prototype.clone = function () {
    var graph = new Graph(this._directed);
    var nodes = this.nodes;
    var edges = this.edges;

    for (var i = 0; i < nodes.length; i++) {
      graph.addNode(nodes[i].id, nodes[i].dataIndex);
    }

    for (var i = 0; i < edges.length; i++) {
      var e = edges[i];
      graph.addEdge(e.node1.id, e.node2.id, e.dataIndex);
    }

    return graph;
  };

  ;
  return Graph;
}();

var GraphNode =
/** @class */
function () {
  function GraphNode(id, dataIndex) {
    this.inEdges = [];
    this.outEdges = [];
    this.edges = [];
    this.dataIndex = -1;
    this.id = id == null ? '' : id;
    this.dataIndex = dataIndex == null ? -1 : dataIndex;
  }
  /**
   * @return {number}
   */


  GraphNode.prototype.degree = function () {
    return this.edges.length;
  };
  /**
   * @return {number}
   */


  GraphNode.prototype.inDegree = function () {
    return this.inEdges.length;
  };
  /**
  * @return {number}
  */


  GraphNode.prototype.outDegree = function () {
    return this.outEdges.length;
  };

  GraphNode.prototype.getModel = function (path) {
    if (this.dataIndex < 0) {
      return;
    }

    var graph = this.hostGraph;
    var itemModel = graph.data.getItemModel(this.dataIndex);
    return itemModel.getModel(path);
  };

  GraphNode.prototype.getAdjacentDataIndices = function () {
    var dataIndices = {
      edge: [],
      node: []
    };

    for (var i = 0; i < this.edges.length; i++) {
      var adjacentEdge = this.edges[i];

      if (adjacentEdge.dataIndex < 0) {
        continue;
      }

      dataIndices.edge.push(adjacentEdge.dataIndex);
      dataIndices.node.push(adjacentEdge.node1.dataIndex, adjacentEdge.node2.dataIndex);
    }

    return dataIndices;
  };

  return GraphNode;
}();

var GraphEdge =
/** @class */
function () {
  function GraphEdge(n1, n2, dataIndex) {
    this.dataIndex = -1;
    this.node1 = n1;
    this.node2 = n2;
    this.dataIndex = dataIndex == null ? -1 : dataIndex;
  }

  GraphEdge.prototype.getModel = function (path) {
    if (this.dataIndex < 0) {
      return;
    }

    var graph = this.hostGraph;
    var itemModel = graph.edgeData.getItemModel(this.dataIndex);
    return itemModel.getModel(path);
  };

  GraphEdge.prototype.getAdjacentDataIndices = function () {
    return {
      edge: [this.dataIndex],
      node: [this.node1.dataIndex, this.node2.dataIndex]
    };
  };

  return GraphEdge;
}();

function createGraphDataProxyMixin(hostName, dataName) {
  return {
    /**
     * @param Default 'value'. can be 'a', 'b', 'c', 'd', 'e'.
     */
    getValue: function (dimension) {
      var data = this[hostName][dataName];
      return data.get(data.getDimension(dimension || 'value'), this.dataIndex);
    },
    // TODO: TYPE stricter type.
    setVisual: function (key, value) {
      this.dataIndex >= 0 && this[hostName][dataName].setItemVisual(this.dataIndex, key, value);
    },
    getVisual: function (key) {
      return this[hostName][dataName].getItemVisual(this.dataIndex, key);
    },
    setLayout: function (layout, merge) {
      this.dataIndex >= 0 && this[hostName][dataName].setItemLayout(this.dataIndex, layout, merge);
    },
    getLayout: function () {
      return this[hostName][dataName].getItemLayout(this.dataIndex);
    },
    getGraphicEl: function () {
      return this[hostName][dataName].getItemGraphicEl(this.dataIndex);
    },
    getRawIndex: function () {
      return this[hostName][dataName].getRawIndex(this.dataIndex);
    }
  };
}

;
;
;
mixin(GraphNode, createGraphDataProxyMixin('hostGraph', 'data'));
mixin(GraphEdge, createGraphDataProxyMixin('hostGraph', 'edgeData'));
/* harmony default export */ const data_Graph = (Graph_Graph);

;// CONCATENATED MODULE: ./node_modules/echarts/lib/data/helper/linkList.js

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/


/**
 * AUTO-GENERATED FILE. DO NOT MODIFY.
 */

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/**
 * Link lists and struct (graph or tree)
 */


var inner = makeInner();

function linkList(opt) {
  var mainData = opt.mainData;
  var datas = opt.datas;

  if (!datas) {
    datas = {
      main: mainData
    };
    opt.datasAttr = {
      main: 'data'
    };
  }

  opt.datas = opt.mainData = null;
  linkAll(mainData, datas, opt); // Porxy data original methods.

  each(datas, function (data) {
    each(mainData.TRANSFERABLE_METHODS, function (methodName) {
      data.wrapMethod(methodName, curry(transferInjection, opt));
    });
  }); // Beyond transfer, additional features should be added to `cloneShallow`.

  mainData.wrapMethod('cloneShallow', curry(cloneShallowInjection, opt)); // Only mainData trigger change, because struct.update may trigger
  // another changable methods, which may bring about dead lock.

  each(mainData.CHANGABLE_METHODS, function (methodName) {
    mainData.wrapMethod(methodName, curry(changeInjection, opt));
  }); // Make sure datas contains mainData.

  assert(datas[mainData.dataType] === mainData);
}

function transferInjection(opt, res) {
  if (isMainData(this)) {
    // Transfer datas to new main data.
    var datas = util_extend({}, inner(this).datas);
    datas[this.dataType] = res;
    linkAll(res, datas, opt);
  } else {
    // Modify the reference in main data to point newData.
    linkSingle(res, this.dataType, inner(this).mainData, opt);
  }

  return res;
}

function changeInjection(opt, res) {
  opt.struct && opt.struct.update();
  return res;
}

function cloneShallowInjection(opt, res) {
  // cloneShallow, which brings about some fragilities, may be inappropriate
  // to be exposed as an API. So for implementation simplicity we can make
  // the restriction that cloneShallow of not-mainData should not be invoked
  // outside, but only be invoked here.
  each(inner(res).datas, function (data, dataType) {
    data !== res && linkSingle(data.cloneShallow(), dataType, res, opt);
  });
  return res;
}
/**
 * Supplement method to List.
 *
 * @public
 * @param [dataType] If not specified, return mainData.
 */


function getLinkedData(dataType) {
  var mainData = inner(this).mainData;
  return dataType == null || mainData == null ? mainData : inner(mainData).datas[dataType];
}
/**
 * Get list of all linked data
 */


function getLinkedDataAll() {
  var mainData = inner(this).mainData;
  return mainData == null ? [{
    data: mainData
  }] : map(keys(inner(mainData).datas), function (type) {
    return {
      type: type,
      data: inner(mainData).datas[type]
    };
  });
}

function isMainData(data) {
  return inner(data).mainData === data;
}

function linkAll(mainData, datas, opt) {
  inner(mainData).datas = {};
  each(datas, function (data, dataType) {
    linkSingle(data, dataType, mainData, opt);
  });
}

function linkSingle(data, dataType, mainData, opt) {
  inner(mainData).datas[dataType] = data;
  inner(data).mainData = mainData;
  data.dataType = dataType;

  if (opt.struct) {
    data[opt.structAttr] = opt.struct;
    opt.struct[opt.datasAttr[dataType]] = data;
  } // Supplement method.


  data.getLinkedData = getLinkedData;
  data.getLinkedDataAll = getLinkedDataAll;
}

/* harmony default export */ const helper_linkList = (linkList);
;// CONCATENATED MODULE: ./src/chart/graphGL/createGraphFromNodeEdge.js





/* harmony default export */ function createGraphFromNodeEdge(nodes, edges, hostModel, directed, beforeLink) {
    var graph = new data_Graph(directed);
    for (var i = 0; i < nodes.length; i++) {
        graph.addNode(util_retrieve.firstNotNull(
            // Id, name, dataIndex
            nodes[i].id, nodes[i].name, i
        ), i);
    }

    var linkNameList = [];
    var validEdges = [];
    var linkCount = 0;
    for (var i = 0; i < edges.length; i++) {
        var link = edges[i];
        var source = link.source;
        var target = link.target;
        // addEdge may fail when source or target not exists
        if (graph.addEdge(source, target, linkCount)) {
            validEdges.push(link);
            linkNameList.push(util_retrieve.firstNotNull(link.id, source + ' > ' + target));
            linkCount++;
        }
    }

    var nodeData;

    // FIXME, support more coordinate systems.
    var dimensionNames = external_echarts_.helper.createDimensions(
        nodes, {
            coordDimensions: ['value']
        }
    );
    nodeData = new external_echarts_.List(dimensionNames, hostModel);
    nodeData.initData(nodes);

    var edgeData = new external_echarts_.List(['value'], hostModel);
    edgeData.initData(validEdges, linkNameList);

    beforeLink && beforeLink(nodeData, edgeData);

    helper_linkList({
        mainData: nodeData,
        struct: graph,
        structAttr: 'graph',
        datas: {node: nodeData, edge: edgeData},
        datasAttr: {node: 'data', edge: 'edgeData'}
    });

    // Update dataIndex of nodes and edges because invalid edge may be removed
    graph.update();

    return graph;
};
;// CONCATENATED MODULE: ./src/chart/graphGL/GraphGLSeries.js




var GraphSeries = external_echarts_.SeriesModel.extend({

    type: 'series.graphGL',

    visualStyleAccessPath: 'itemStyle',

    hasSymbolVisual: true,

    init: function (option) {
        GraphSeries.superApply(this, 'init', arguments);

        // Provide data for legend select
        this.legendDataProvider = function () {
            return this._categoriesData;
        };

        this._updateCategoriesData();
    },

    mergeOption: function (option) {
        GraphSeries.superApply(this, 'mergeOption', arguments);

        this._updateCategoriesData();
    },

    getFormattedLabel: function (dataIndex, status, dataType, dimIndex) {
        var text = util_format.getFormattedLabel(this, dataIndex, status, dataType, dimIndex);
        if (text == null) {
            var data = this.getData();
            var lastDim = data.dimensions[data.dimensions.length - 1];
            text = data.get(lastDim, dataIndex);
        }
        return text;
    },

    getInitialData: function (option, ecModel) {
        var edges = option.edges || option.links || [];
        var nodes = option.data || option.nodes || [];
        var self = this;

        if (nodes && edges) {
            return createGraphFromNodeEdge(nodes, edges, this, true, beforeLink).data;
        }

        function beforeLink(nodeData, edgeData) {
            // Overwrite nodeData.getItemModel to
            nodeData.wrapMethod('getItemModel', function (model) {
                const categoriesModels = self._categoriesModels;
                const categoryIdx = model.getShallow('category');
                const categoryModel = categoriesModels[categoryIdx];
                if (categoryModel) {
                    categoryModel.parentModel = model.parentModel;
                    model.parentModel = categoryModel;
                }
                return model;
            });

            // TODO Inherit resolveParentPath by default in Model#getModel?
            const oldGetModel = ecModel.getModel([]).getModel;
            function newGetModel(path, parentModel) {
                const model = oldGetModel.call(this, path, parentModel);
                model.resolveParentPath = resolveParentPath;
                return model;
            }

            edgeData.wrapMethod('getItemModel', function (model) {
                model.resolveParentPath = resolveParentPath;
                model.getModel = newGetModel;
                return model;
            });

            function resolveParentPath(pathArr) {
                if (pathArr && (pathArr[0] === 'label' || pathArr[1] === 'label')) {
                    const newPathArr = pathArr.slice();
                    if (pathArr[0] === 'label') {
                        newPathArr[0] = 'edgeLabel';
                    }
                    else if (pathArr[1] === 'label') {
                        newPathArr[1] = 'edgeLabel';
                    }
                    return newPathArr;
                }
                return pathArr;
            }
        }
    },

    /**
     * @return {module:echarts/data/Graph}
     */
    getGraph: function () {
        return this.getData().graph;
    },

    /**
     * @return {module:echarts/data/List}
     */
    getEdgeData: function () {
        return this.getGraph().edgeData;
    },

    /**
     * @return {module:echarts/data/List}
     */
    getCategoriesData: function () {
        return this._categoriesData;
    },

    /**
     * @override
     */
    formatTooltip: function (dataIndex, multipleSeries, dataType) {
        if (dataType === 'edge') {
            var nodeData = this.getData();
            var params = this.getDataParams(dataIndex, dataType);
            var edge = nodeData.graph.getEdgeByIndex(dataIndex);
            var sourceName = nodeData.getName(edge.node1.dataIndex);
            var targetName = nodeData.getName(edge.node2.dataIndex);

            var html = [];
            sourceName != null && html.push(sourceName);
            targetName != null && html.push(targetName);
            html = external_echarts_.format.encodeHTML(html.join(' > '));

            if (params.value) {
                html += ' : ' + external_echarts_.format.encodeHTML(params.value);
            }
            return html;
        }
        else { // dataType === 'node' or empty
            return GraphSeries.superApply(this, 'formatTooltip', arguments);
        }
    },

    _updateCategoriesData: function () {
        var categories = (this.option.categories || []).map(function (category) {
            // Data must has value
            return category.value != null ? category : Object.assign({
                value: 0
            }, category);
        });
        var categoriesData = new external_echarts_.List(['value'], this);
        categoriesData.initData(categories);

        this._categoriesData = categoriesData;

        this._categoriesModels = categoriesData.mapArray(function (idx) {
            return categoriesData.getItemModel(idx, true);
        });
    },

    setView: function (payload) {
        if (payload.zoom != null) {
            this.option.zoom = payload.zoom;
        }
        if (payload.offset != null) {
            this.option.offset = payload.offset;
        }
    },

    setNodePosition: function (points) {
        for (var i = 0; i < points.length / 2; i++) {
            var x = points[i * 2];
            var y = points[i * 2 + 1];

            var opt = this.getData().getRawDataItem(i);
            opt.x = x;
            opt.y = y;
        }
    },

    isAnimationEnabled: function () {
        return GraphSeries.superCall(this, 'isAnimationEnabled')
            // Not enable animation when do force layout
            && !(this.get('layout') === 'force' && this.get('force.layoutAnimation'));
    },

    defaultOption: {
        zlevel: 10,
        z: 2,

        legendHoverLink: true,

        // Only support forceAtlas2
        layout: 'forceAtlas2',

        // Configuration of force directed layout
        forceAtlas2: {
            initLayout: null,

            GPU: true,

            steps: 1,

            // barnesHutOptimize

            // Maxp layout steps.
            maxSteps: 1000,

            repulsionByDegree: true,
            linLogMode: false,
            strongGravityMode: false,
            gravity: 1.0,
            // scaling: 1.0,

            edgeWeightInfluence: 1.0,

            // Edge weight range.
            edgeWeight: [1, 4],
            // Node weight range.
            nodeWeight: [1, 4],

            // jitterTolerence: 0.1,
            preventOverlap: false,
            gravityCenter: null
        },

        focusNodeAdjacency: true,

        focusNodeAdjacencyOn: 'mouseover',

        left: 'center',
        top: 'center',
        // right: null,
        // bottom: null,
        // width: '80%',
        // height: '80%',

        symbol: 'circle',
        symbolSize: 5,

        roam: false,

        // Default on center of graph
        center: null,

        zoom: 1,

        // categories: [],

        // data: []
        // Or
        // nodes: []
        //
        // links: []
        // Or
        // edges: []

        label: {
            show: false,
            formatter: '{b}',
            position: 'right',
            distance: 5,
            textStyle: {
                fontSize: 14
            }
        },

        itemStyle: {},

        lineStyle: {
            color: '#aaa',
            width: 1,
            opacity: 0.5
        },

        emphasis: {
            label: {
                show: true
            }
        },

        animation: false
    }
});

/* harmony default export */ const GraphGLSeries = (GraphSeries);
;// CONCATENATED MODULE: ./src/util/geometry/Lines2D.js
/**
 * Lines geometry
 * Use screen space projected lines lineWidth > MAX_LINE_WIDTH
 * https://mattdesl.svbtle.com/drawing-lines-is-hard
 * @module echarts-gl/util/geometry/LinesGeometry
 * @author Yi Shen(http://github.com/pissang)
 */





var Lines2D_vec2 = dep_glmatrix.vec2;

// var CURVE_RECURSION_LIMIT = 8;
// var CURVE_COLLINEAR_EPSILON = 40;

var Lines2D_sampleLinePoints = [[0, 0], [1, 1]];
/**
 * @constructor
 * @alias module:echarts-gl/util/geometry/LinesGeometry
 * @extends clay.Geometry
 */

var Lines2D_LinesGeometry = src_Geometry.extend(function () {
    return {

        segmentScale: 4,

        dynamic: true,
        /**
         * Need to use mesh to expand lines if lineWidth > MAX_LINE_WIDTH
         */
        useNativeLine: true,

        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 2, 'POSITION'),
            normal: new src_Geometry.Attribute('normal', 'float', 2),
            offset: new src_Geometry.Attribute('offset', 'float', 1),
            color: new src_Geometry.Attribute('color', 'float', 4, 'COLOR')
        }
    };
},
/** @lends module: echarts-gl/util/geometry/LinesGeometry.prototype */
{

    /**
     * Reset offset
     */
    resetOffset: function () {
        this._vertexOffset = 0;
        this._faceOffset = 0;

        this._itemVertexOffsets = [];
    },

    /**
     * @param {number} nVertex
     */
    setVertexCount: function (nVertex) {
        var attributes = this.attributes;
        if (this.vertexCount !== nVertex) {
            attributes.position.init(nVertex);
            attributes.color.init(nVertex);

            if (!this.useNativeLine) {
                attributes.offset.init(nVertex);
                attributes.normal.init(nVertex);
            }

            if (nVertex > 0xffff) {
                if (this.indices instanceof Uint16Array) {
                    this.indices = new Uint32Array(this.indices);
                }
            }
            else {
                if (this.indices instanceof Uint32Array) {
                    this.indices = new Uint16Array(this.indices);
                }
            }
        }
    },

    /**
     * @param {number} nTriangle
     */
    setTriangleCount: function (nTriangle) {
        if (this.triangleCount !== nTriangle) {
            if (nTriangle === 0) {
                this.indices = null;
            }
            else {
                this.indices = this.vertexCount > 0xffff ? new Uint32Array(nTriangle * 3) : new Uint16Array(nTriangle * 3);
            }
        }
    },

    _getCubicCurveApproxStep: function (p0, p1, p2, p3) {
        var len = Lines2D_vec2.dist(p0, p1) + Lines2D_vec2.dist(p2, p1) + Lines2D_vec2.dist(p3, p2);
        var step = 1 / (len + 1) * this.segmentScale;
        return step;
    },

    /**
     * Get vertex count of cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @return number
     */
    getCubicCurveVertexCount: function (p0, p1, p2, p3) {
        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);
        var segCount = Math.ceil(1 / step);
        if (!this.useNativeLine) {
            return segCount * 2 + 2;
        }
        else {
            return segCount * 2;
        }
    },

    /**
     * Get face count of cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @return number
     */
    getCubicCurveTriangleCount: function (p0, p1, p2, p3) {
        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);
        var segCount = Math.ceil(1 / step);
        if (!this.useNativeLine) {
            return segCount * 2;
        }
        else {
            return 0;
        }
    },

    /**
     * Get vertex count of line
     * @return {number}
     */
    getLineVertexCount: function () {
        return this.getPolylineVertexCount(Lines2D_sampleLinePoints);
    },

    /**
     * Get face count of line
     * @return {number}
     */
    getLineTriangleCount: function () {
        return this.getPolylineTriangleCount(Lines2D_sampleLinePoints);
    },

    /**
     * Get how many vertices will polyline take.
     * @type {number|Array} points Can be a 1d/2d list of points, or a number of points amount.
     * @return {number}
     */
    getPolylineVertexCount: function (points) {
        var pointsLen;
        if (typeof points === 'number') {
            pointsLen = points;
        }
        else {
            var is2DArray = typeof points[0] !== 'number';
            pointsLen = is2DArray ? points.length : (points.length / 2);
        }
        return !this.useNativeLine ? ((pointsLen - 1) * 2 + 2) : (pointsLen - 1) * 2;
    },

    /**
     * Get how many triangles will polyline take.
     * @type {number|Array} points Can be a 1d/2d list of points, or a number of points amount.
     * @return {number}
     */
    getPolylineTriangleCount: function (points) {
        var pointsLen;
        if (typeof points === 'number') {
            pointsLen = points;
        }
        else {
            var is2DArray = typeof points[0] !== 'number';
            pointsLen = is2DArray ? points.length : (points.length / 2);
        }
        return !this.useNativeLine ? (pointsLen - 1) * 2 : 0;
    },

    /**
     * Add a cubic curve
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} p2
     * @param {Array.<number>} p3
     * @param {Array.<number>} color
     * @param {number} [lineWidth=1]
     */
    addCubicCurve: function (p0, p1, p2, p3, color, lineWidth) {
        if (lineWidth == null) {
            lineWidth = 1;
        }
        // incremental interpolation
        // http://antigrain.com/research/bezier_interpolation/index.html#PAGE_BEZIER_INTERPOLATION
        var x0 = p0[0], y0 = p0[1];
        var x1 = p1[0], y1 = p1[1];
        var x2 = p2[0], y2 = p2[1];
        var x3 = p3[0], y3 = p3[1];

        var step = this._getCubicCurveApproxStep(p0, p1, p2, p3);

        var step2 = step * step;
        var step3 = step2 * step;

        var pre1 = 3.0 * step;
        var pre2 = 3.0 * step2;
        var pre4 = 6.0 * step2;
        var pre5 = 6.0 * step3;

        var tmp1x = x0 - x1 * 2.0 + x2;
        var tmp1y = y0 - y1 * 2.0 + y2;

        var tmp2x = (x1 - x2) * 3.0 - x0 + x3;
        var tmp2y = (y1 - y2) * 3.0 - y0 + y3;

        var fx = x0;
        var fy = y0;

        var dfx = (x1 - x0) * pre1 + tmp1x * pre2 + tmp2x * step3;
        var dfy = (y1 - y0) * pre1 + tmp1y * pre2 + tmp2y * step3;

        var ddfx = tmp1x * pre4 + tmp2x * pre5;
        var ddfy = tmp1y * pre4 + tmp2y * pre5;

        var dddfx = tmp2x * pre5;
        var dddfy = tmp2y * pre5;

        var t = 0;

        var k = 0;
        var segCount = Math.ceil(1 / step);

        var points = new Float32Array((segCount + 1) * 3);
        var points = [];
        var offset = 0;
        for (var k = 0; k < segCount + 1; k++) {
            points[offset++] = fx;
            points[offset++] = fy;

            fx += dfx; fy += dfy;
            dfx += ddfx; dfy += ddfy;
            ddfx += dddfx; ddfy += dddfy;
            t += step;

            if (t > 1) {
                fx = dfx > 0 ? Math.min(fx, x3) : Math.max(fx, x3);
                fy = dfy > 0 ? Math.min(fy, y3) : Math.max(fy, y3);
            }
        }

        this.addPolyline(points, color, lineWidth);
    },

    /**
     * Add a straight line
     * @param {Array.<number>} p0
     * @param {Array.<number>} p1
     * @param {Array.<number>} color
     * @param {number} [lineWidth=1]
     */
    addLine: function (p0, p1, color, lineWidth) {
        this.addPolyline([p0, p1], color, lineWidth);
    },

    /**
     * Add a straight line
     * @param {Array.<Array> | Array.<number>} points
     * @param {Array.<number> | Array.<Array>} color
     * @param {number} [lineWidth=1]
     * @param {number} [arrayOffset=0]
     * @param {number} [pointsCount] Default to be amount of points in the first argument
     */
    addPolyline: (function () {
        var dirA = Lines2D_vec2.create();
        var dirB = Lines2D_vec2.create();
        var normal = Lines2D_vec2.create();
        var tangent = Lines2D_vec2.create();
        var point = [], nextPoint = [], prevPoint = [];
        return function (points, color, lineWidth, arrayOffset, pointsCount) {
            if (!points.length) {
                return;
            }
            var is2DArray = typeof points[0] !== 'number';
            if (pointsCount == null) {
                pointsCount = is2DArray ? points.length : points.length / 2;
            }
            if (pointsCount < 2) {
                return;
            }
            if (arrayOffset == null) {
                arrayOffset = 0;
            }
            if (lineWidth == null) {
                lineWidth = 1;
            }

            this._itemVertexOffsets.push(this._vertexOffset);

            var notSharingColor = is2DArray
                ? typeof color[0] !== 'number'
                : color.length / 4 === pointsCount;

            var positionAttr = this.attributes.position;
            var colorAttr = this.attributes.color;
            var offsetAttr = this.attributes.offset;
            var normalAttr = this.attributes.normal;
            var indices = this.indices;

            var vertexOffset = this._vertexOffset;
            var pointColor;
            for (var k = 0; k < pointsCount; k++) {
                if (is2DArray) {
                    point = points[k + arrayOffset];
                    if (notSharingColor) {
                        pointColor = color[k + arrayOffset];
                    }
                    else {
                        pointColor = color;
                    }
                }
                else {
                    var k2 = k * 2 + arrayOffset;
                    point = point || [];
                    point[0] = points[k2];
                    point[1] = points[k2 + 1];

                    if (notSharingColor) {
                        var k4 = k * 4 + arrayOffset;
                        pointColor = pointColor || [];
                        pointColor[0] = color[k4];
                        pointColor[1] = color[k4 + 1];
                        pointColor[2] = color[k4 + 2];
                        pointColor[3] = color[k4 + 3];
                    }
                    else {
                        pointColor = color;
                    }
                }
                if (!this.useNativeLine) {
                    var offset;
                    if (k < pointsCount - 1) {
                        if (is2DArray) {
                            Lines2D_vec2.copy(nextPoint, points[k + 1]);
                        }
                        else {
                            var k2 = (k + 1) * 2 + arrayOffset;
                            nextPoint = nextPoint || [];
                            nextPoint[0] = points[k2];
                            nextPoint[1] = points[k2 + 1];
                        }
                        // TODO In case dir is (0, 0)
                        // TODO miterLimit
                        if (k > 0) {
                            Lines2D_vec2.sub(dirA, point, prevPoint);
                            Lines2D_vec2.sub(dirB, nextPoint, point);
                            Lines2D_vec2.normalize(dirA, dirA);
                            Lines2D_vec2.normalize(dirB, dirB);
                            Lines2D_vec2.add(tangent, dirA, dirB);
                            Lines2D_vec2.normalize(tangent, tangent);
                            var miter = lineWidth / 2 * Math.min(1 / Lines2D_vec2.dot(dirA, tangent), 2);
                            normal[0] = -tangent[1];
                            normal[1] = tangent[0];

                            offset = miter;
                        }
                        else {
                            Lines2D_vec2.sub(dirA, nextPoint, point);
                            Lines2D_vec2.normalize(dirA, dirA);

                            normal[0] = -dirA[1];
                            normal[1] = dirA[0];

                            offset = lineWidth / 2;
                        }

                    }
                    else {
                        Lines2D_vec2.sub(dirA, point, prevPoint);
                        Lines2D_vec2.normalize(dirA, dirA);

                        normal[0] = -dirA[1];
                        normal[1] = dirA[0];

                        offset = lineWidth / 2;
                    }
                    normalAttr.set(vertexOffset, normal);
                    normalAttr.set(vertexOffset + 1, normal);
                    offsetAttr.set(vertexOffset, offset);
                    offsetAttr.set(vertexOffset + 1, -offset);

                    Lines2D_vec2.copy(prevPoint, point);

                    positionAttr.set(vertexOffset, point);
                    positionAttr.set(vertexOffset + 1, point);

                    colorAttr.set(vertexOffset, pointColor);
                    colorAttr.set(vertexOffset + 1, pointColor);

                    vertexOffset += 2;
                }
                else {
                    if (k > 1) {
                        positionAttr.copy(vertexOffset, vertexOffset - 1);
                        colorAttr.copy(vertexOffset, vertexOffset - 1);
                        vertexOffset++;
                    }
                }

                if (!this.useNativeLine) {
                    if (k > 0) {
                        var idx3 = this._faceOffset * 3;
                        var indices = this.indices;
                        // 0-----2
                        // 1-----3
                        // 0->1->2, 1->3->2
                        indices[idx3] = vertexOffset - 4;
                        indices[idx3 + 1] = vertexOffset - 3;
                        indices[idx3 + 2] = vertexOffset - 2;

                        indices[idx3 + 3] = vertexOffset - 3;
                        indices[idx3 + 4] = vertexOffset - 1;
                        indices[idx3 + 5] = vertexOffset - 2;

                        this._faceOffset += 2;
                    }
                }
                else {
                    colorAttr.set(vertexOffset, pointColor);
                    positionAttr.set(vertexOffset, point);
                    vertexOffset++;
                }
            }

            this._vertexOffset = vertexOffset;
        };
    })(),

    /**
     * Set color of single line.
     */
    setItemColor: function (idx, color) {
        var startOffset = this._itemVertexOffsets[idx];
        var endOffset = idx < this._itemVertexOffsets.length - 1 ? this._itemVertexOffsets[idx + 1] : this._vertexOffset;

        for (var i = startOffset; i < endOffset; i++) {
            this.attributes.color.set(i, color);
        }
        this.dirty('color');
    }
});

external_echarts_.util.defaults(Lines2D_LinesGeometry.prototype, dynamicConvertMixin);

/* harmony default export */ const Lines2D = (Lines2D_LinesGeometry);
;// CONCATENATED MODULE: ./src/chart/graphGL/forceAtlas2.glsl.js
/* harmony default export */ const forceAtlas2_glsl = ("@export ecgl.forceAtlas2.updateNodeRepulsion\n\n#define NODE_COUNT 0\n\nuniform sampler2D positionTex;\n\nuniform vec2 textureSize;\nuniform float gravity;\nuniform float scaling;\nuniform vec2 gravityCenter;\n\nuniform bool strongGravityMode;\nuniform bool preventOverlap;\n\nvarying vec2 v_Texcoord;\n\nvoid main() {\n\n vec4 n0 = texture2D(positionTex, v_Texcoord);\n\n vec2 force = vec2(0.0);\n for (int i = 0; i < NODE_COUNT; i++) {\n vec2 uv = vec2(\n mod(float(i), textureSize.x) / (textureSize.x - 1.0),\n floor(float(i) / textureSize.x) / (textureSize.y - 1.0)\n );\n vec4 n1 = texture2D(positionTex, uv);\n\n vec2 dir = n0.xy - n1.xy;\n float d2 = dot(dir, dir);\n\n if (d2 > 0.0) {\n float factor = 0.0;\n if (preventOverlap) {\n float d = sqrt(d2);\n d = d - n0.w - n1.w;\n if (d > 0.0) {\n factor = scaling * n0.z * n1.z / (d * d);\n }\n else if (d < 0.0) {\n factor = scaling * 100.0 * n0.z * n1.z;\n }\n }\n else {\n factor = scaling * n0.z * n1.z / d2;\n }\n force += dir * factor;\n }\n }\n\n vec2 dir = gravityCenter - n0.xy;\n float d = 1.0;\n if (!strongGravityMode) {\n d = length(dir);\n }\n\n force += dir * n0.z * gravity / (d + 1.0);\n\n gl_FragColor = vec4(force, 0.0, 1.0);\n}\n@end\n\n@export ecgl.forceAtlas2.updateEdgeAttraction.vertex\n\nattribute vec2 node1;\nattribute vec2 node2;\nattribute float weight;\n\nuniform sampler2D positionTex;\nuniform float edgeWeightInfluence;\nuniform bool preventOverlap;\nuniform bool linLogMode;\n\nuniform vec2 windowSize: WINDOW_SIZE;\n\nvarying vec2 v_Force;\n\nvoid main() {\n\n vec4 n0 = texture2D(positionTex, node1);\n vec4 n1 = texture2D(positionTex, node2);\n\n vec2 dir = n1.xy - n0.xy;\n float d = length(dir);\n float w;\n if (edgeWeightInfluence == 0.0) {\n w = 1.0;\n }\n else if (edgeWeightInfluence == 1.0) {\n w = weight;\n }\n else {\n w = pow(weight, edgeWeightInfluence);\n }\n vec2 offset = vec2(1.0 / windowSize.x, 1.0 / windowSize.y);\n vec2 scale = vec2((windowSize.x - 1.0) / windowSize.x, (windowSize.y - 1.0) / windowSize.y);\n vec2 pos = node1 * scale * 2.0 - 1.0;\n gl_Position = vec4(pos + offset, 0.0, 1.0);\n gl_PointSize = 1.0;\n\n float factor;\n if (preventOverlap) {\n d = d - n1.w - n0.w;\n }\n if (d <= 0.0) {\n v_Force = vec2(0.0);\n return;\n }\n\n if (linLogMode) {\n factor = w * log(d) / d;\n }\n else {\n factor = w;\n }\n v_Force = dir * factor;\n}\n@end\n\n@export ecgl.forceAtlas2.updateEdgeAttraction.fragment\n\nvarying vec2 v_Force;\n\nvoid main() {\n gl_FragColor = vec4(v_Force, 0.0, 0.0);\n}\n@end\n\n@export ecgl.forceAtlas2.calcWeightedSum.vertex\n\nattribute vec2 node;\n\nvarying vec2 v_NodeUv;\n\nvoid main() {\n\n v_NodeUv = node;\n gl_Position = vec4(0.0, 0.0, 0.0, 1.0);\n gl_PointSize = 1.0;\n}\n@end\n\n@export ecgl.forceAtlas2.calcWeightedSum.fragment\n\nvarying vec2 v_NodeUv;\n\nuniform sampler2D positionTex;\nuniform sampler2D forceTex;\nuniform sampler2D forcePrevTex;\n\nvoid main() {\n vec2 force = texture2D(forceTex, v_NodeUv).rg;\n vec2 forcePrev = texture2D(forcePrevTex, v_NodeUv).rg;\n\n float mass = texture2D(positionTex, v_NodeUv).z;\n float swing = length(force - forcePrev) * mass;\n float traction = length(force + forcePrev) * 0.5 * mass;\n\n gl_FragColor = vec4(swing, traction, 0.0, 0.0);\n}\n@end\n\n@export ecgl.forceAtlas2.calcGlobalSpeed\n\nuniform sampler2D globalSpeedPrevTex;\nuniform sampler2D weightedSumTex;\nuniform float jitterTolerence;\n\nvoid main() {\n vec2 weightedSum = texture2D(weightedSumTex, vec2(0.5)).xy;\n float prevGlobalSpeed = texture2D(globalSpeedPrevTex, vec2(0.5)).x;\n float globalSpeed = jitterTolerence * jitterTolerence\n * weightedSum.y / weightedSum.x;\n if (prevGlobalSpeed > 0.0) {\n globalSpeed = min(globalSpeed / prevGlobalSpeed, 1.5) * prevGlobalSpeed;\n }\n gl_FragColor = vec4(globalSpeed, 0.0, 0.0, 1.0);\n}\n@end\n\n@export ecgl.forceAtlas2.updatePosition\n\nuniform sampler2D forceTex;\nuniform sampler2D forcePrevTex;\nuniform sampler2D positionTex;\nuniform sampler2D globalSpeedTex;\n\nvarying vec2 v_Texcoord;\n\nvoid main() {\n vec2 force = texture2D(forceTex, v_Texcoord).xy;\n vec2 forcePrev = texture2D(forcePrevTex, v_Texcoord).xy;\n vec4 node = texture2D(positionTex, v_Texcoord);\n\n float globalSpeed = texture2D(globalSpeedTex, vec2(0.5)).r;\n float swing = length(force - forcePrev);\n float speed = 0.1 * globalSpeed / (0.1 + globalSpeed * sqrt(swing));\n\n float df = length(force);\n if (df > 0.0) {\n speed = min(df * speed, 10.0) / df;\n\n gl_FragColor = vec4(node.xy + speed * force, node.zw);\n }\n else {\n gl_FragColor = node;\n }\n}\n@end\n\n@export ecgl.forceAtlas2.edges.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nattribute vec2 node;\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n\nuniform sampler2D positionTex;\n\nvoid main()\n{\n gl_Position = worldViewProjection * vec4(\n texture2D(positionTex, node).xy, -10.0, 1.0\n );\n v_Color = a_Color;\n}\n@end\n\n@export ecgl.forceAtlas2.edges.fragment\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nvarying vec4 v_Color;\nvoid main() {\n gl_FragColor = color * v_Color;\n}\n@end");

;// CONCATENATED MODULE: ./src/chart/graphGL/ForceAtlas2GPU.js





util_graphicGL.Shader.import(forceAtlas2_glsl);

var defaultConfigs = {
    repulsionByDegree: true,
    linLogMode: false,

    strongGravityMode: false,
    gravity: 1.0,

    scaling: 1.0,

    edgeWeightInfluence: 1.0,

    jitterTolerence: 0.1,

    preventOverlap: false,

    dissuadeHubs: false,

    gravityCenter: null
};

function ForceAtlas2GPU(options) {

    var textureOpt = {
        type: util_graphicGL.Texture.FLOAT,
        minFilter: util_graphicGL.Texture.NEAREST,
        magFilter: util_graphicGL.Texture.NEAREST
    };

    this._positionSourceTex = new util_graphicGL.Texture2D(textureOpt);
    this._positionSourceTex.flipY = false;

    this._positionTex = new util_graphicGL.Texture2D(textureOpt);
    this._positionPrevTex = new util_graphicGL.Texture2D(textureOpt);
    this._forceTex = new util_graphicGL.Texture2D(textureOpt);
    this._forcePrevTex = new util_graphicGL.Texture2D(textureOpt);

    this._weightedSumTex = new util_graphicGL.Texture2D(textureOpt);
    this._weightedSumTex.width = this._weightedSumTex.height = 1;

    this._globalSpeedTex = new util_graphicGL.Texture2D(textureOpt);
    this._globalSpeedPrevTex = new util_graphicGL.Texture2D(textureOpt);
    this._globalSpeedTex.width = this._globalSpeedTex.height = 1;
    this._globalSpeedPrevTex.width = this._globalSpeedPrevTex.height = 1;

    this._nodeRepulsionPass = new compositor_Pass({
        fragment: util_graphicGL.Shader.source('ecgl.forceAtlas2.updateNodeRepulsion')
    });
    this._positionPass = new compositor_Pass({
        fragment: util_graphicGL.Shader.source('ecgl.forceAtlas2.updatePosition')
    });
    this._globalSpeedPass = new compositor_Pass({
        fragment: util_graphicGL.Shader.source('ecgl.forceAtlas2.calcGlobalSpeed')
    });
    this._copyPass = new compositor_Pass({
        fragment: util_graphicGL.Shader.source('clay.compositor.output')
    });

    var additiveBlend = function (gl) {
        gl.blendEquation(gl.FUNC_ADD);
        gl.blendFunc(gl.ONE, gl.ONE);
    };
    this._edgeForceMesh = new util_graphicGL.Mesh({
        geometry: new util_graphicGL.Geometry({
            attributes: {
                node1: new util_graphicGL.Geometry.Attribute('node1', 'float', 2),
                node2: new util_graphicGL.Geometry.Attribute('node2', 'float', 2),
                weight: new util_graphicGL.Geometry.Attribute('weight', 'float', 1)
            },
            dynamic: true,
            mainAttribute: 'node1'
        }),
        material: new util_graphicGL.Material({
            transparent: true,
            shader: util_graphicGL.createShader('ecgl.forceAtlas2.updateEdgeAttraction'),
            blend: additiveBlend,
            depthMask: false,
            depthText: false
        }),
        mode: util_graphicGL.Mesh.POINTS
    });
    this._weightedSumMesh = new util_graphicGL.Mesh({
        geometry: new util_graphicGL.Geometry({
            attributes: {
                node: new util_graphicGL.Geometry.Attribute('node', 'float', 2)
            },
            dynamic: true,
            mainAttribute: 'node'
        }),
        material: new util_graphicGL.Material({
            transparent: true,
            shader: util_graphicGL.createShader('ecgl.forceAtlas2.calcWeightedSum'),
            blend: additiveBlend,
            depthMask: false,
            depthText: false
        }),
        mode: util_graphicGL.Mesh.POINTS
    });

    this._framebuffer = new src_FrameBuffer({
        depthBuffer: false
    });

    this._dummyCamera = new util_graphicGL.OrthographicCamera({
        left: -1, right: 1,
        top: 1, bottom: -1,
        near: 0, far: 100
    });

    this._globalSpeed = 0;
}

ForceAtlas2GPU.prototype.updateOption = function (options) {

    // Default config
    for (var name in defaultConfigs) {
        this[name] = defaultConfigs[name];
    }

    // Config according to data scale
    var nNodes = this._nodes.length;
    if (nNodes > 50000) {
        this.jitterTolerence = 10;
    }
    else if (nNodes > 5000) {
        this.jitterTolerence = 1;
    }
    else {
        this.jitterTolerence = 0.1;
    }

    if (nNodes > 100) {
        this.scaling = 2.0;
    }
    else {
        this.scaling = 10.0;
    }

    // this.edgeWeightInfluence = 1;
    // this.gravity = 1;
    // this.strongGravityMode = false;
    if (options) {
        for (var name in defaultConfigs) {
            if (options[name] != null) {
                this[name] = options[name];
            }
        }
    }

    if (this.repulsionByDegree) {
        var positionBuffer = this._positionSourceTex.pixels;

        for (var i = 0; i < this._nodes.length; i++) {
            positionBuffer[i * 4 + 2] = (this._nodes[i].degree || 0) + 1;
        }
    }
};

ForceAtlas2GPU.prototype._updateGravityCenter = function (options) {
    var nodes = this._nodes;
    var edges = this._edges;

    if (!this.gravityCenter) {
        var min = [Infinity, Infinity];
        var max = [-Infinity, -Infinity];
        for (var i = 0; i < nodes.length; i++) {
            min[0] = Math.min(nodes[i].x, min[0]);
            min[1] = Math.min(nodes[i].y, min[1]);
            max[0] = Math.max(nodes[i].x, max[0]);
            max[1] = Math.max(nodes[i].y, max[1]);
        }

        this._gravityCenter = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5];
    }
    else {
        this._gravityCenter = this.gravityCenter;
    }
    // Update inDegree, outDegree
    for (var i = 0; i < edges.length; i++) {
        var node1 = edges[i].node1;
        var node2 = edges[i].node2;

        nodes[node1].degree = (nodes[node1].degree || 0) + 1;
        nodes[node2].degree = (nodes[node2].degree || 0) + 1;
    }
};
/**
 * @param {Array.<Object>} [{ x, y, mass }] nodes
 * @param {Array.<Object>} [{ node1, node2, weight }] edges
 */
ForceAtlas2GPU.prototype.initData = function (nodes, edges) {

    this._nodes = nodes;
    this._edges = edges;

    this._updateGravityCenter();

    var textureWidth = Math.ceil(Math.sqrt(nodes.length));
    var textureHeight = textureWidth;
    var positionBuffer = new Float32Array(textureWidth * textureHeight * 4);

    this._resize(textureWidth, textureHeight);

    var offset = 0;
    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        positionBuffer[offset++] = node.x || 0;
        positionBuffer[offset++] = node.y || 0;
        positionBuffer[offset++] = node.mass || 1;
        positionBuffer[offset++] = node.size || 1;
    }
    this._positionSourceTex.pixels = positionBuffer;

    var edgeGeometry = this._edgeForceMesh.geometry;
    var edgeLen = edges.length;
    edgeGeometry.attributes.node1.init(edgeLen * 2);
    edgeGeometry.attributes.node2.init(edgeLen * 2);
    edgeGeometry.attributes.weight.init(edgeLen * 2);

    var uv = [];

    for (var i = 0; i < edges.length; i++) {
        var attributes = edgeGeometry.attributes;
        var weight = edges[i].weight;
        if (weight == null) {
            weight = 1;
        }
        // Two way.
        attributes.node1.set(i, this.getNodeUV(edges[i].node1, uv));
        attributes.node2.set(i, this.getNodeUV(edges[i].node2, uv));
        attributes.weight.set(i, weight);

        attributes.node1.set(i + edgeLen, this.getNodeUV(edges[i].node2, uv));
        attributes.node2.set(i + edgeLen, this.getNodeUV(edges[i].node1, uv));
        attributes.weight.set(i + edgeLen, weight);
    }

    var weigtedSumGeo = this._weightedSumMesh.geometry;
    weigtedSumGeo.attributes.node.init(nodes.length);
    for (var i = 0; i < nodes.length; i++) {
        weigtedSumGeo.attributes.node.set(i, this.getNodeUV(i, uv));
    }

    edgeGeometry.dirty();
    weigtedSumGeo.dirty();

    this._nodeRepulsionPass.material.define('fragment', 'NODE_COUNT', nodes.length);
    this._nodeRepulsionPass.material.setUniform('textureSize', [textureWidth, textureHeight]);

    this._inited = false;

    this._frame = 0;
};

ForceAtlas2GPU.prototype.getNodes = function () {
    return this._nodes;
};
ForceAtlas2GPU.prototype.getEdges = function () {
    return this._edges;
};

ForceAtlas2GPU.prototype.step = function (renderer) {
    if (!this._inited) {
        this._initFromSource(renderer);
        this._inited = true;
    }

    this._frame++;

    this._framebuffer.attach(this._forceTex);
    this._framebuffer.bind(renderer);
    var nodeRepulsionPass = this._nodeRepulsionPass;
    // Calc node repulsion, gravity
    nodeRepulsionPass.setUniform('strongGravityMode', this.strongGravityMode);
    nodeRepulsionPass.setUniform('gravity', this.gravity);
    nodeRepulsionPass.setUniform('gravityCenter', this._gravityCenter);
    nodeRepulsionPass.setUniform('scaling', this.scaling);
    nodeRepulsionPass.setUniform('preventOverlap', this.preventOverlap);
    nodeRepulsionPass.setUniform('positionTex', this._positionPrevTex);
    nodeRepulsionPass.render(renderer);

    // Calc edge attraction force
    var edgeForceMesh = this._edgeForceMesh;
    edgeForceMesh.material.set('linLogMode', this.linLogMode);
    edgeForceMesh.material.set('edgeWeightInfluence', this.edgeWeightInfluence);
    edgeForceMesh.material.set('preventOverlap', this.preventOverlap);
    edgeForceMesh.material.set('positionTex', this._positionPrevTex);
    renderer.gl.enable(renderer.gl.BLEND);
    renderer.renderPass([edgeForceMesh], this._dummyCamera);

    // Calc weighted sum.
    this._framebuffer.attach(this._weightedSumTex);
    renderer.gl.clearColor(0, 0, 0, 0);
    renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT);
    renderer.gl.enable(renderer.gl.BLEND);
    var weightedSumMesh = this._weightedSumMesh;
    weightedSumMesh.material.set('positionTex', this._positionPrevTex);
    weightedSumMesh.material.set('forceTex', this._forceTex);
    weightedSumMesh.material.set('forcePrevTex', this._forcePrevTex);
    renderer.renderPass([weightedSumMesh], this._dummyCamera);

    // Calc global speed.
    this._framebuffer.attach(this._globalSpeedTex);
    var globalSpeedPass = this._globalSpeedPass;
    globalSpeedPass.setUniform('globalSpeedPrevTex', this._globalSpeedPrevTex);
    globalSpeedPass.setUniform('weightedSumTex', this._weightedSumTex);
    globalSpeedPass.setUniform('jitterTolerence', this.jitterTolerence);
    renderer.gl.disable(renderer.gl.BLEND);
    globalSpeedPass.render(renderer);

    // Update position.
    var positionPass = this._positionPass;
    this._framebuffer.attach(this._positionTex);
    positionPass.setUniform('globalSpeedTex', this._globalSpeedTex);
    positionPass.setUniform('positionTex', this._positionPrevTex);
    positionPass.setUniform('forceTex', this._forceTex);
    positionPass.setUniform('forcePrevTex', this._forcePrevTex);
    positionPass.render(renderer);

    this._framebuffer.unbind(renderer);

    this._swapTexture();
};

ForceAtlas2GPU.prototype.update = function (renderer, steps, cb) {
    if (steps == null) {
        steps = 1;
    }
    steps = Math.max(steps, 1);

    for (var i = 0; i < steps; i++) {
        this.step(renderer);
    }

    cb && cb();
};

ForceAtlas2GPU.prototype.getNodePositionTexture = function () {
    return this._inited
        // Texture already been swapped.
        ? this._positionPrevTex
        : this._positionSourceTex;
};

ForceAtlas2GPU.prototype.getNodeUV = function (nodeIndex, uv) {
    uv = uv || [];
    var textureWidth = this._positionTex.width;
    var textureHeight = this._positionTex.height;
    uv[0] = (nodeIndex % textureWidth) / (textureWidth - 1);
    uv[1] = Math.floor(nodeIndex / textureWidth) / (textureHeight - 1) || 0;
    return uv;
};

ForceAtlas2GPU.prototype.getNodePosition = function (renderer, out) {
    var positionArr = this._positionArr;
    var width = this._positionTex.width;
    var height = this._positionTex.height;
    var size = width * height;
    if (!positionArr || positionArr.length !== size * 4) {
        positionArr = this._positionArr = new Float32Array(size * 4);
    }
    this._framebuffer.bind(renderer);
    this._framebuffer.attach(this._positionPrevTex);
    renderer.gl.readPixels(
        0, 0, width, height,
        renderer.gl.RGBA, renderer.gl.FLOAT,
        positionArr
    );
    this._framebuffer.unbind(renderer);
    if (!out) {
        out = new Float32Array(this._nodes.length * 2);
    }
    for (var i = 0; i < this._nodes.length; i++) {
        out[i * 2] = positionArr[i * 4];
        out[i * 2 + 1] = positionArr[i * 4 + 1];
    }
    return out;
};

ForceAtlas2GPU.prototype.getTextureData = function (renderer, textureName) {
    var tex = this['_' + textureName + 'Tex'];
    var width = tex.width;
    var height = tex.height;
    this._framebuffer.bind(renderer);
    this._framebuffer.attach(tex);
    var arr = new Float32Array(width * height * 4);
    renderer.gl.readPixels(0, 0, width, height, renderer.gl.RGBA, renderer.gl.FLOAT, arr);
    this._framebuffer.unbind(renderer);
    return arr;
};

ForceAtlas2GPU.prototype.getTextureSize = function () {
    return {
        width: this._positionTex.width,
        height: this._positionTex.height
    };
};

ForceAtlas2GPU.prototype.isFinished = function (maxSteps) {
    return this._frame > maxSteps;
};

ForceAtlas2GPU.prototype._swapTexture = function () {
    var tmp = this._positionPrevTex;
    this._positionPrevTex = this._positionTex;
    this._positionTex = tmp;

    var tmp = this._forcePrevTex;
    this._forcePrevTex = this._forceTex;
    this._forceTex = tmp;

    var tmp = this._globalSpeedPrevTex;
    this._globalSpeedPrevTex = this._globalSpeedTex;
    this._globalSpeedTex = tmp;
};

ForceAtlas2GPU.prototype._initFromSource = function (renderer) {
    this._framebuffer.attach(this._positionPrevTex);
    this._framebuffer.bind(renderer);
    this._copyPass.setUniform('texture', this._positionSourceTex);
    this._copyPass.render(renderer);

    renderer.gl.clearColor(0, 0, 0, 0);
    this._framebuffer.attach(this._forcePrevTex);
    renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT);
    this._framebuffer.attach(this._globalSpeedPrevTex);
    renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT);

    this._framebuffer.unbind(renderer);
};

ForceAtlas2GPU.prototype._resize = function (width, height) {
    ['_positionSourceTex', '_positionTex', '_positionPrevTex', '_forceTex', '_forcePrevTex'].forEach(function (texName) {
        this[texName].width = width;
        this[texName].height = height;
        this[texName].dirty();
    }, this);
};

ForceAtlas2GPU.prototype.dispose = function (renderer) {
    this._framebuffer.dispose(renderer);

    this._copyPass.dispose(renderer);
    this._nodeRepulsionPass.dispose(renderer);
    this._positionPass.dispose(renderer);
    this._globalSpeedPass.dispose(renderer);

    this._edgeForceMesh.geometry.dispose(renderer);
    this._weightedSumMesh.geometry.dispose(renderer);

    this._positionSourceTex.dispose(renderer);
    this._positionTex.dispose(renderer);
    this._positionPrevTex.dispose(renderer);
    this._forceTex.dispose(renderer);
    this._forcePrevTex.dispose(renderer);
    this._weightedSumTex.dispose(renderer);
    this._globalSpeedTex.dispose(renderer);
    this._globalSpeedPrevTex.dispose(renderer);
};

/* harmony default export */ const graphGL_ForceAtlas2GPU = (ForceAtlas2GPU);
;// CONCATENATED MODULE: ./src/chart/graphGL/forceAtlas2Worker.js
/****************************
 * Vector2 math functions
 ***************************/

function forceAtlas2Worker() {
    var vec2 = {
        create: function() {
            return new Float32Array(2);
        },
        dist: function(a, b) {
            var x = b[0] - a[0];
            var y = b[1] - a[1];
            return Math.sqrt(x*x + y*y);
        },
        len: function(a) {
            var x = a[0];
            var y = a[1];
            return Math.sqrt(x*x + y*y);
        },
        scaleAndAdd: function(out, a, b, scale) {
            out[0] = a[0] + b[0] * scale;
            out[1] = a[1] + b[1] * scale;
            return out;
        },
        scale: function(out, a, b) {
            out[0] = a[0] * b;
            out[1] = a[1] * b;
            return out;
        },
        add: function(out, a, b) {
            out[0] = a[0] + b[0];
            out[1] = a[1] + b[1];
            return out;
        },
        sub: function(out, a, b) {
            out[0] = a[0] - b[0];
            out[1] = a[1] - b[1];
            return out;
        },
        normalize: function(out, a) {
            var x = a[0];
            var y = a[1];
            var len = x*x + y*y;
            if (len > 0) {
                //TODO: evaluate use of glm_invsqrt here?
                len = 1 / Math.sqrt(len);
                out[0] = a[0] * len;
                out[1] = a[1] * len;
            }
            return out;
        },
        negate: function(out, a) {
            out[0] = -a[0];
            out[1] = -a[1];
            return out;
        },
        copy: function(out, a) {
            out[0] = a[0];
            out[1] = a[1];
            return out;
        },
        set: function(out, x, y) {
            out[0] = x;
            out[1] = y;
            return out;
        }
    }

    /****************************
     * Class: Region
     ***************************/

    function Region() {

        this.subRegions = [];

        this.nSubRegions = 0;

        this.node = null;

        this.mass = 0;

        this.centerOfMass = null;

        this.bbox = new Float32Array(4);

        this.size = 0;
    }

    var regionProto = Region.prototype;

    // Reset before update
    regionProto.beforeUpdate = function() {
        for (var i = 0; i < this.nSubRegions; i++) {
            this.subRegions[i].beforeUpdate();
        }
        this.mass = 0;
        if (this.centerOfMass) {
            this.centerOfMass[0] = 0;
            this.centerOfMass[1] = 0;
        }
        this.nSubRegions = 0;
        this.node = null;
    };
    // Clear after update
    regionProto.afterUpdate = function() {
        this.subRegions.length = this.nSubRegions;
        for (var i = 0; i < this.nSubRegions; i++) {
            this.subRegions[i].afterUpdate();
        }
    };

    regionProto.addNode = function(node) {
        if (this.nSubRegions === 0) {
            if (this.node == null) {
                this.node = node;
                return;
            }
            // Already have node, subdivide self.
            else {
                this._addNodeToSubRegion(this.node);
                this.node = null;
            }
        }
        this._addNodeToSubRegion(node);

        this._updateCenterOfMass(node);
    };

    regionProto.findSubRegion = function(x, y) {
        for (var i = 0; i < this.nSubRegions; i++) {
            var region = this.subRegions[i];
            if (region.contain(x, y)) {
                return region;
            }
        }
    };

    regionProto.contain = function(x, y) {
        return this.bbox[0] <= x
            && this.bbox[2] >= x
            && this.bbox[1] <= y
            && this.bbox[3] >= y;
    };

    regionProto.setBBox = function(minX, minY, maxX, maxY) {
        // Min
        this.bbox[0] = minX;
        this.bbox[1] = minY;
        // Max
        this.bbox[2] = maxX;
        this.bbox[3] = maxY;

        this.size = (maxX - minX + maxY - minY) / 2;
    };

    regionProto._newSubRegion = function() {
        var subRegion = this.subRegions[this.nSubRegions];
        if (!subRegion) {
            subRegion = new Region();
            this.subRegions[this.nSubRegions] = subRegion;
        }
        this.nSubRegions++;
        return subRegion;
    };

    regionProto._addNodeToSubRegion = function(node) {
        var subRegion = this.findSubRegion(node.position[0], node.position[1]);
        var bbox = this.bbox;
        if (!subRegion) {
            var cx = (bbox[0] + bbox[2]) / 2;
            var cy = (bbox[1] + bbox[3]) / 2;
            var w = (bbox[2] - bbox[0]) / 2;
            var h = (bbox[3] - bbox[1]) / 2;

            var xi = node.position[0] >= cx ? 1 : 0;
            var yi = node.position[1] >= cy ? 1 : 0;

            var subRegion = this._newSubRegion();
            // Min
            subRegion.setBBox(
                // Min
                xi * w + bbox[0],
                yi * h + bbox[1],
                // Max
                (xi + 1) * w + bbox[0],
                (yi + 1) * h + bbox[1]
            );
        }

        subRegion.addNode(node);
    };

    regionProto._updateCenterOfMass = function(node) {
        // Incrementally update
        if (this.centerOfMass == null) {
            this.centerOfMass = new Float32Array(2);
        }
        var x = this.centerOfMass[0] * this.mass;
        var y = this.centerOfMass[1] * this.mass;
        x += node.position[0] * node.mass;
        y += node.position[1] * node.mass;
        this.mass += node.mass;
        this.centerOfMass[0] = x / this.mass;
        this.centerOfMass[1] = y / this.mass;
    };

    /****************************
     * Class: Graph Node
     ***************************/
    function GraphNode() {
        this.position = new Float32Array(2);

        this.force = vec2.create();
        this.forcePrev = vec2.create();

        // If repulsionByDegree is true
        //  mass = inDegree + outDegree + 1
        // Else
        //  mass is manually set
        this.mass = 1;

        this.inDegree = 0;
        this.outDegree = 0;

        // Optional
        // this.size = 1;
    }

    /****************************
     * Class: Graph Edge
     ***************************/
    function GraphEdge(source, target) {
        this.source = source;
        this.target = target;

        this.weight = 1;
    }

    /****************************
     * Class: ForceStlas2
     ***************************/
    function ForceAtlas2() {
        //-------------
        // Configs

        // If auto settings is true
        //  barnesHutOptimize,
        //  barnesHutTheta,
        //  scaling,
        //  jitterTolerence
        // Will be set by the system automatically
        //  preventOverlap will be set false
        //  if node size is not given
        this.autoSettings = true;

        // Barnes Hut
        // http://arborjs.org/docs/barnes-hut
        this.barnesHutOptimize = true;
        this.barnesHutTheta = 1.5;

        // Force Atlas2 Configs
        this.repulsionByDegree = true;

        this.linLogMode = false;

        this.strongGravityMode = false;
        this.gravity = 1.0;

        this.scaling = 1.0;

        this.edgeWeightInfluence = 1.0;
        this.jitterTolerence = 0.1;

        // TODO
        this.preventOverlap = false;
        this.dissuadeHubs = false;

        //
        this.rootRegion = new Region();
        this.rootRegion.centerOfMass = vec2.create();

        this.nodes = [];

        this.edges = [];

        this.bbox = new Float32Array(4);

        this.gravityCenter = null;

        this._massArr = null;

        this._swingingArr = null;

        this._sizeArr = null;

        this._globalSpeed = 0;
    }

    var forceAtlas2Proto = ForceAtlas2.prototype;

    forceAtlas2Proto.initNodes = function(positionArr, massArr, sizeArr) {
        var nNodes = massArr.length;
        this.nodes.length = 0;
        var haveSize = typeof(sizeArr) != 'undefined';
        for (var i = 0; i < nNodes; i++) {
            var node = new GraphNode();
            node.position[0] = positionArr[i * 2];
            node.position[1] = positionArr[i * 2 + 1];
            node.mass = massArr[i];
            if (haveSize) {
                node.size = sizeArr[i];
            }
            this.nodes.push(node);
        }

        this._massArr = massArr;
        this._swingingArr = new Float32Array(nNodes);

        if (haveSize) {
            this._sizeArr = sizeArr;
        }
    };

    forceAtlas2Proto.initEdges = function(edgeArr, edgeWeightArr) {
        var nEdges = edgeArr.length / 2;
        this.edges.length = 0;
        for (var i = 0; i < nEdges; i++) {
            var sIdx = edgeArr[i * 2];
            var tIdx = edgeArr[i * 2 + 1];
            var sNode = this.nodes[sIdx];
            var tNode = this.nodes[tIdx];

            if (!sNode || !tNode) {
                console.error('Node not exists, try initNodes before initEdges');
                return;
            }
            sNode.outDegree++;
            tNode.inDegree++;
            var edge = new GraphEdge(sNode, tNode);

            if (edgeWeightArr) {
                edge.weight = edgeWeightArr[i];
            }

            this.edges.push(edge);
        }
    }

    forceAtlas2Proto.updateSettings = function() {
        if (this.repulsionByDegree) {
            for (var i = 0; i < this.nodes.length; i++) {
                var node = this.nodes[i];
                node.mass = node.inDegree + node.outDegree + 1;
            }
        }
        else {
            for (var i = 0; i < this.nodes.length; i++) {
                var node = this.nodes[i];
                node.mass = this._massArr[i];
            }
        }
    };

    forceAtlas2Proto.update = function() {
        var nNodes = this.nodes.length;

        this.updateSettings();

        this.updateBBox();

        // Update region
        if (this.barnesHutOptimize) {
            this.rootRegion.setBBox(
                this.bbox[0], this.bbox[1],
                this.bbox[2], this.bbox[3]
            );

            this.rootRegion.beforeUpdate();
            for (var i = 0; i < nNodes; i++) {
                this.rootRegion.addNode(this.nodes[i]);
            }
            this.rootRegion.afterUpdate();
        }

        // Reset forces
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            vec2.copy(node.forcePrev, node.force);
            vec2.set(node.force, 0, 0);
        }

        // Compute forces
        // Repulsion
        for (var i = 0; i < nNodes; i++) {
            var na = this.nodes[i];
            if (this.barnesHutOptimize) {
                this.applyRegionToNodeRepulsion(this.rootRegion, na);
            }
            else {
                for (var j = i + 1; j < nNodes; j++) {
                    var nb = this.nodes[j];
                    this.applyNodeToNodeRepulsion(na, nb, false);
                }
            }

            // Gravity
            if (this.gravity > 0) {
                if (this.strongGravityMode) {
                    this.applyNodeStrongGravity(na);
                }
                else {
                    this.applyNodeGravity(na);
                }
            }
        }

        // Attraction
        for (var i = 0; i < this.edges.length; i++) {
            this.applyEdgeAttraction(this.edges[i]);
        }

        // Handle swinging
        var swingWeightedSum = 0;
        var tractionWeightedSum = 0;
        var tmp = vec2.create();
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            var swing = vec2.dist(node.force, node.forcePrev);
            swingWeightedSum += swing * node.mass;

            vec2.add(tmp, node.force, node.forcePrev);
            var traction = vec2.len(tmp) * 0.5;
            tractionWeightedSum += traction * node.mass;

            // Save the value for using later
            this._swingingArr[i] = swing;
        }
        var globalSpeed = this.jitterTolerence * this.jitterTolerence
                        * tractionWeightedSum / swingWeightedSum;
        // NB: During our tests we observed that an excessive rise of the global speed could have a negative impact.
        // That’s why we limited the increase of global speed s(t)(G) to 50% of the previous step s(t−1)(G).
        if (this._globalSpeed > 0) {
            globalSpeed = Math.min(globalSpeed / this._globalSpeed, 1.5) * this._globalSpeed;
        }
        this._globalSpeed = globalSpeed;

        // Apply forces
        for (var i = 0; i < nNodes; i++) {
            var node = this.nodes[i];
            var swing = this._swingingArr[i];

            var speed = 0.1 * globalSpeed / (1 + globalSpeed * Math.sqrt(swing));

            // Additional constraint to prevent local speed gets too high
            var df = vec2.len(node.force);
            if (df > 0) {
                speed = Math.min(df * speed, 10) / df;
                vec2.scaleAndAdd(node.position, node.position, node.force, speed);
            }
        }
    };

    forceAtlas2Proto.applyRegionToNodeRepulsion = (function() {
        var v = vec2.create();
        return function applyRegionToNodeRepulsion(region, node) {
            if (region.node) { // Region is a leaf
                this.applyNodeToNodeRepulsion(region.node, node, true);
            }
            else {
                vec2.sub(v, node.position, region.centerOfMass);
                var d2 = v[0] * v[0] + v[1] * v[1];
                if (d2 > this.barnesHutTheta * region.size * region.size) {
                    var factor = this.scaling * node.mass * region.mass / d2;
                    vec2.scaleAndAdd(node.force, node.force, v, factor);
                }
                else {
                    for (var i = 0; i < region.nSubRegions; i++) {
                        this.applyRegionToNodeRepulsion(region.subRegions[i], node);
                    }
                }
            }
        }
    })();

    forceAtlas2Proto.applyNodeToNodeRepulsion = (function() {
        var v = vec2.create();
        return function applyNodeToNodeRepulsion(na, nb, oneWay) {
            if (na == nb) {
                return;
            }
            vec2.sub(v, na.position, nb.position);
            var d2 = v[0] * v[0] + v[1] * v[1];

            // PENDING
            if (d2 === 0) {
                return;
            }

            var factor;
            if (this.preventOverlap) {
                var d = Math.sqrt(d2);
                d = d - na.size - nb.size;
                if (d > 0) {
                    factor = this.scaling * na.mass * nb.mass / (d * d);
                }
                else if (d < 0) {
                    // A stronger repulsion if overlap
                    factor = this.scaling * 100 * na.mass * nb.mass;
                }
                else {
                    // No repulsion
                    return;
                }
            }
            else {
                // Divide factor by an extra `d` to normalize the `v`
                factor = this.scaling * na.mass * nb.mass / d2;
            }

            vec2.scaleAndAdd(na.force, na.force, v, factor);
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor);
        }
    })();

    forceAtlas2Proto.applyEdgeAttraction = (function() {
        var v = vec2.create();
        return function applyEdgeAttraction(edge) {
            var na = edge.source;
            var nb = edge.target;

            vec2.sub(v, na.position, nb.position);
            var d = vec2.len(v);

            var w;
            if (this.edgeWeightInfluence === 0) {
                w = 1;
            }
            else if (this.edgeWeightInfluence === 1) {
                w = edge.weight;
            }
            else {
                w = Math.pow(edge.weight, this.edgeWeightInfluence);
            }

            var factor;

            if (this.preventOverlap) {
                d = d - na.size - nb.size;
                if (d <= 0) {
                    // No attraction
                    return;
                }
            }

            if (this.linLogMode) {
                // Divide factor by an extra `d` to normalize the `v`
                factor = - w * Math.log(d + 1) / (d + 1);
            }
            else {
                factor = - w;
            }
            vec2.scaleAndAdd(na.force, na.force, v, factor);
            vec2.scaleAndAdd(nb.force, nb.force, v, -factor);
        }
    })();

    forceAtlas2Proto.applyNodeGravity = (function() {
        var v = vec2.create();
        return function(node) {
            vec2.sub(v, this.gravityCenter, node.position);
            var d = vec2.len(v);
            vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass / (d + 1));
        }
    })();

    forceAtlas2Proto.applyNodeStrongGravity = (function() {
        var v = vec2.create();
        return function(node) {
            vec2.sub(v, this.gravityCenter, node.position);
            vec2.scaleAndAdd(node.force, node.force, v, this.gravity * node.mass);
        }
    })();

    forceAtlas2Proto.updateBBox = function() {
        var minX = Infinity;
        var minY = Infinity;
        var maxX = -Infinity;
        var maxY = -Infinity;
        for (var i = 0; i < this.nodes.length; i++) {
            var pos = this.nodes[i].position;
            minX = Math.min(minX, pos[0]);
            minY = Math.min(minY, pos[1]);
            maxX = Math.max(maxX, pos[0]);
            maxY = Math.max(maxY, pos[1]);
        }
        this.bbox[0] = minX;
        this.bbox[1] = minY;
        this.bbox[2] = maxX;
        this.bbox[3] = maxY;
    };

    forceAtlas2Proto.getGlobalSpeed = function () {
        return this._globalSpeed;
    }

    /****************************
     * Main process
     ***************************/

    var forceAtlas2 = null;

    self.onmessage = function(e) {
        switch(e.data.cmd) {
            case 'init':
                forceAtlas2 = new ForceAtlas2();
                forceAtlas2.initNodes(e.data.nodesPosition, e.data.nodesMass, e.data.nodesSize);
                forceAtlas2.initEdges(e.data.edges, e.data.edgesWeight);
                break;
            case 'updateConfig':
                if (forceAtlas2) {
                    for (var name in e.data.config) {
                        forceAtlas2[name] = e.data.config[name];
                    }
                }
                break;
            case 'update':
                var steps = e.data.steps;
                if (forceAtlas2) {
                    for (var i = 0; i < steps; i++) {
                        forceAtlas2.update();
                    }

                    var nNodes = forceAtlas2.nodes.length;
                    var positionArr = new Float32Array(nNodes * 2);
                    // Callback
                    for (var i = 0; i < nNodes; i++) {
                        var node = forceAtlas2.nodes[i];
                        positionArr[i * 2] = node.position[0];
                        positionArr[i * 2 + 1] = node.position[1];
                    }
                    self.postMessage({
                        buffer: positionArr.buffer,
                        globalSpeed: forceAtlas2.getGlobalSpeed()
                    }, [positionArr.buffer]);
                }
                else {
                    // Not initialzied yet
                    var emptyArr = new Float32Array();
                    // Post transfer object
                    self.postMessage({
                        buffer: emptyArr.buffer,
                        globalSpeed: forceAtlas2.getGlobalSpeed()
                    }, [emptyArr.buffer]);
                }
                break;
        }
    }
}

/* harmony default export */ const graphGL_forceAtlas2Worker = (forceAtlas2Worker);
;// CONCATENATED MODULE: ./src/chart/graphGL/ForceAtlas2.js



var workerUrl = graphGL_forceAtlas2Worker.toString();
workerUrl = workerUrl.slice(workerUrl.indexOf('{') + 1, workerUrl.lastIndexOf('}'));

var ForceAtlas2_defaultConfigs = {

    barnesHutOptimize: true,
    barnesHutTheta: 1.5,

    repulsionByDegree: true,
    linLogMode: false,

    strongGravityMode: false,
    gravity: 1.0,

    scaling: 1.0,

    edgeWeightInfluence: 1.0,

    jitterTolerence: 0.1,

    preventOverlap: false,

    dissuadeHubs: false,

    gravityCenter: null
};

var ForceAtlas2 = function (options) {

    for (var name in ForceAtlas2_defaultConfigs) {
        this[name] = ForceAtlas2_defaultConfigs[name];
    }

    if (options) {
        for (var name in options) {
            this[name] = options[name];
        }
    }

    this._nodes = [];
    this._edges = [];

    this._disposed = false;

    this._positionTex = new src_Texture2D({
        type: src_Texture.FLOAT,
        flipY: false,
        minFilter: src_Texture.NEAREST,
        magFilter: src_Texture.NEAREST
    });
};

ForceAtlas2.prototype.initData = function (nodes, edges) {

    var bb = new Blob([workerUrl]);
    var blobURL = window.URL.createObjectURL(bb);

    this._worker = new Worker(blobURL);

    this._worker.onmessage = this._$onupdate.bind(this);

    this._nodes = nodes;
    this._edges = edges;
    this._frame = 0;

    var nNodes = nodes.length;
    var nEdges = edges.length;

    var positionArr = new Float32Array(nNodes * 2);
    var massArr = new Float32Array(nNodes);
    var sizeArr = new Float32Array(nNodes);

    var edgeArr = new Float32Array(nEdges * 2);
    var edgeWeightArr = new Float32Array(nEdges);

    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];

        positionArr[i * 2] = node.x;
        positionArr[i * 2 + 1] = node.y;

        massArr[i] = node.mass == null ? 1 : node.mass;
        sizeArr[i] = node.size == null ? 1 : node.size;
    }

    for (var i = 0; i < edges.length; i++) {
        var edge = edges[i];

        var source = edge.node1;
        var target = edge.node2;

        edgeArr[i * 2] = source;
        edgeArr[i * 2 + 1] = target;

        edgeWeightArr[i] = edge.weight == null ? 1 : edge.weight;
    }


    var textureWidth = Math.ceil(Math.sqrt(nodes.length));
    var textureHeight = textureWidth;
    var pixels = new Float32Array(textureWidth * textureHeight * 4);
    var positionTex = this._positionTex;
    positionTex.width = textureWidth;
    positionTex.height = textureHeight;
    positionTex.pixels = pixels;

    this._worker.postMessage({
        cmd: 'init',
        nodesPosition: positionArr,
        nodesMass: massArr,
        nodesSize: sizeArr,
        edges: edgeArr,
        edgesWeight: edgeWeightArr
    });

    this._globalSpeed = Infinity;
};

ForceAtlas2.prototype.updateOption = function (options) {
    var config = {};
    // Default config
    for (var name in ForceAtlas2_defaultConfigs) {
        config[name] = ForceAtlas2_defaultConfigs[name];
    }

    var nodes = this._nodes;
    var edges = this._edges;

    // Config according to data scale
    var nNodes = nodes.length;
    if (nNodes > 50000) {
        config.jitterTolerence = 10;
    }
    else if (nNodes > 5000) {
        config.jitterTolerence = 1;
    }
    else {
        config.jitterTolerence = 0.1;
    }

    if (nNodes > 100) {
        config.scaling = 2.0;
    }
    else {
        config.scaling = 10.0;
    }
    if (nNodes > 1000) {
        config.barnesHutOptimize = true;
    }
    else {
        config.barnesHutOptimize = false;
    }

    if (options) {
        for (var name in ForceAtlas2_defaultConfigs) {
            if (options[name] != null) {
                config[name] = options[name];
            }
        }
    }

    if (!config.gravityCenter) {
        var min = [Infinity, Infinity];
        var max = [-Infinity, -Infinity];
        for (var i = 0; i < nodes.length; i++) {
            min[0] = Math.min(nodes[i].x, min[0]);
            min[1] = Math.min(nodes[i].y, min[1]);
            max[0] = Math.max(nodes[i].x, max[0]);
            max[1] = Math.max(nodes[i].y, max[1]);
        }

        config.gravityCenter = [(min[0] + max[0]) * 0.5, (min[1] + max[1]) * 0.5];
    }

    // Update inDegree, outDegree
    for (var i = 0; i < edges.length; i++) {
        var node1 = edges[i].node1;
        var node2 = edges[i].node2;

        nodes[node1].degree = (nodes[node1].degree || 0) + 1;
        nodes[node2].degree = (nodes[node2].degree || 0) + 1;
    }

    if (this._worker) {
        this._worker.postMessage({
            cmd: 'updateConfig',
            config: config
        });
    }
};

// Steps per call, to keep sync with rendering
ForceAtlas2.prototype.update = function (renderer, steps, cb) {
    if (steps == null) {
        steps = 1;
    }
    steps = Math.max(steps, 1);

    this._frame += steps;
    this._onupdate = cb;

    if (this._worker) {
        this._worker.postMessage({
            cmd: 'update',
            steps: Math.round(steps)
        });
    }
};

ForceAtlas2.prototype._$onupdate = function (e) {
    // Incase the worker keep postMessage of last frame after it is disposed
    if (this._disposed) {
        return;
    }

    var positionArr = new Float32Array(e.data.buffer);
    this._globalSpeed = e.data.globalSpeed;

    this._positionArr = positionArr;

    this._updateTexture(positionArr);

    this._onupdate && this._onupdate();
};

ForceAtlas2.prototype.getNodePositionTexture = function () {
    return this._positionTex;
};

ForceAtlas2.prototype.getNodeUV = function (nodeIndex, uv) {
    uv = uv || [];
    var textureWidth = this._positionTex.width;
    var textureHeight = this._positionTex.height;
    uv[0] = (nodeIndex % textureWidth) / (textureWidth - 1);
    uv[1] = Math.floor(nodeIndex / textureWidth) / (textureHeight - 1);
    return uv;
};

ForceAtlas2.prototype.getNodes = function () {
    return this._nodes;
};
ForceAtlas2.prototype.getEdges = function () {
    return this._edges;
};
ForceAtlas2.prototype.isFinished = function (maxSteps) {
    return this._frame > maxSteps;
};

ForceAtlas2.prototype.getNodePosition = function (renderer, out) {
    if (!out) {
        out = new Float32Array(this._nodes.length * 2);
    }
    if (this._positionArr) {
        for (var i = 0; i < this._positionArr.length; i++) {
            out[i] = this._positionArr[i];
        }
    }
    return out;
};

ForceAtlas2.prototype._updateTexture = function (positionArr) {
    var pixels = this._positionTex.pixels;
    var offset = 0;
    for (var i = 0; i < positionArr.length;){
        pixels[offset++] = positionArr[i++];
        pixels[offset++] = positionArr[i++];
        pixels[offset++] = 1;
        pixels[offset++] = 1;
    }
    this._positionTex.dirty();
};

ForceAtlas2.prototype.dispose = function (renderer) {
    this._disposed = true;
    this._worker = null;
};

/* harmony default export */ const graphGL_ForceAtlas2 = (ForceAtlas2);
;// CONCATENATED MODULE: ./src/util/Roam2DControl.js




/**
 * @alias module:echarts-gl/util/Roam2DControl
 */
var Roam2DControl = core_Base.extend(function () {

    return {
        /**
         * @type {module:zrender~ZRender}
         */
        zr: null,

        /**
         * @type {module:echarts-gl/core/ViewGL}
         */
        viewGL: null,

        minZoom: 0.2,

        maxZoom: 5,

        _needsUpdate: false,

        _dx: 0,
        _dy: 0,

        _zoom: 1
    };
}, function () {
    // Each Roam2DControl has it's own handler
    this._mouseDownHandler = this._mouseDownHandler.bind(this);
    this._mouseWheelHandler = this._mouseWheelHandler.bind(this);
    this._mouseMoveHandler = this._mouseMoveHandler.bind(this);
    this._mouseUpHandler = this._mouseUpHandler.bind(this);
    this._update = this._update.bind(this);
}, {

    init: function () {
        var zr = this.zr;

        zr.on('mousedown', this._mouseDownHandler);
        zr.on('mousewheel', this._mouseWheelHandler);
        zr.on('globalout', this._mouseUpHandler);

        zr.animation.on('frame', this._update);
    },

    setTarget: function (target) {
        this._target = target;
    },

    setZoom: function (zoom) {
        this._zoom = Math.max(Math.min(
            zoom, this.maxZoom
        ), this.minZoom);
        this._needsUpdate = true;
    },

    setOffset: function (offset) {
        this._dx = offset[0];
        this._dy = offset[1];

        this._needsUpdate = true;
    },

    getZoom: function () {
        return this._zoom;
    },

    getOffset: function () {
        return [this._dx, this._dy];
    },

    _update: function () {
        if (!this._target) {
            return;
        }
        if (!this._needsUpdate) {
            return;
        }

        var target = this._target;

        var scale = this._zoom;

        target.position.x = this._dx;
        target.position.y = this._dy;

        target.scale.set(scale, scale, scale);

        this.zr.refresh();

        this._needsUpdate = false;

        this.trigger('update');
    },

    _mouseDownHandler: function (e) {
        if (e.target) {
            return;
        }

        var x = e.offsetX;
        var y = e.offsetY;
        if (this.viewGL && !this.viewGL.containPoint(x, y)) {
            return;
        }

        this.zr.on('mousemove', this._mouseMoveHandler);
        this.zr.on('mouseup', this._mouseUpHandler);

        var pos = this._convertPos(x, y);

        this._x = pos.x;
        this._y = pos.y;
    },

    // Convert pos from screen space to viewspace.
    _convertPos: function (x, y) {

        var camera = this.viewGL.camera;
        var viewport = this.viewGL.viewport;
        // PENDING
        return {
            x: (x - viewport.x) / viewport.width * (camera.right - camera.left) + camera.left,
            y: (y - viewport.y) / viewport.height * (camera.bottom - camera.top) + camera.top
        };
    },

    _mouseMoveHandler: function (e) {

        var pos = this._convertPos(e.offsetX, e.offsetY);

        this._dx += pos.x - this._x;
        this._dy += pos.y - this._y;

        this._x = pos.x;
        this._y = pos.y;

        this._needsUpdate = true;
    },

    _mouseUpHandler: function (e) {
        this.zr.off('mousemove', this._mouseMoveHandler);
        this.zr.off('mouseup', this._mouseUpHandler);
    },

    _mouseWheelHandler: function (e) {
        e = e.event;
        var delta = e.wheelDelta // Webkit
                || -e.detail; // Firefox
        if (delta === 0) {
            return;
        }

        var x = e.offsetX;
        var y = e.offsetY;
        if (this.viewGL && !this.viewGL.containPoint(x, y)) {
            return;
        }

        var zoomScale = delta > 0 ? 1.1 : 0.9;
        var newZoom = Math.max(Math.min(
            this._zoom * zoomScale, this.maxZoom
        ), this.minZoom);
        zoomScale = newZoom / this._zoom;

        var pos = this._convertPos(x, y);

        var fixX = (pos.x - this._dx) * (zoomScale - 1);
        var fixY = (pos.y - this._dy) * (zoomScale - 1);

        this._dx -= fixX;
        this._dy -= fixY;

        this._zoom = newZoom;

        this._needsUpdate = true;
    },

    dispose: function () {

        var zr = this.zr;
        zr.off('mousedown', this._mouseDownHandler);
        zr.off('mousemove', this._mouseMoveHandler);
        zr.off('mouseup', this._mouseUpHandler);
        zr.off('mousewheel', this._mouseWheelHandler);
        zr.off('globalout', this._mouseUpHandler);

        zr.animation.off('frame', this._update);
    }
});

/* harmony default export */ const util_Roam2DControl = (Roam2DControl);
;// CONCATENATED MODULE: ./src/util/shader/lines2D.glsl.js
/* harmony default export */ const lines2D_glsl = ("@export ecgl.lines2D.vertex\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nattribute vec2 position: POSITION;\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n\n#ifdef POSITIONTEXTURE_ENABLED\nuniform sampler2D positionTexture;\n#endif\n\nvoid main()\n{\n gl_Position = worldViewProjection * vec4(position, -10.0, 1.0);\n\n v_Color = a_Color;\n}\n\n@end\n\n@export ecgl.lines2D.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nvarying vec4 v_Color;\n\nvoid main()\n{\n gl_FragColor = color * v_Color;\n}\n@end\n\n\n@export ecgl.meshLines2D.vertex\n\nattribute vec2 position: POSITION;\nattribute vec2 normal;\nattribute float offset;\nattribute vec4 a_Color : COLOR;\n\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec4 viewport : VIEWPORT;\n\nvarying vec4 v_Color;\nvarying float v_Miter;\n\nvoid main()\n{\n vec4 p2 = worldViewProjection * vec4(position + normal, -10.0, 1.0);\n gl_Position = worldViewProjection * vec4(position, -10.0, 1.0);\n\n p2.xy /= p2.w;\n gl_Position.xy /= gl_Position.w;\n\n vec2 N = normalize(p2.xy - gl_Position.xy);\n gl_Position.xy += N * offset / viewport.zw * 2.0;\n\n gl_Position.xy *= gl_Position.w;\n\n v_Color = a_Color;\n}\n@end\n\n\n@export ecgl.meshLines2D.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\n\nvarying vec4 v_Color;\nvarying float v_Miter;\n\nvoid main()\n{\n gl_FragColor = color * v_Color;\n}\n\n@end");

;// CONCATENATED MODULE: ./src/chart/graphGL/GraphGLView.js












var GraphGLView_vec2 = dep_glmatrix.vec2;






util_graphicGL.Shader.import(lines2D_glsl);

var globalLayoutId = 1;

/* harmony default export */ const GraphGLView = (external_echarts_.ChartView.extend({

    type: 'graphGL',

    __ecgl__: true,

    init: function (ecModel, api) {

        this.groupGL = new util_graphicGL.Node();
        this.viewGL = new core_ViewGL('orthographic');
        this.viewGL.camera.left = this.viewGL.camera.right = 0;

        this.viewGL.add(this.groupGL);

        this._pointsBuilder = new common_PointsBuilder(true, api);

        // Mesh used during force directed layout.
        this._forceEdgesMesh = new util_graphicGL.Mesh({
            material: new util_graphicGL.Material({
                shader: util_graphicGL.createShader('ecgl.forceAtlas2.edges'),
                transparent: true,
                depthMask: false,
                depthTest: false
            }),
            $ignorePicking: true,
            geometry: new util_graphicGL.Geometry({
                attributes: {
                    node: new util_graphicGL.Geometry.Attribute('node', 'float', 2),
                    color: new util_graphicGL.Geometry.Attribute('color', 'float', 4, 'COLOR')
                },
                dynamic: true,
                mainAttribute: 'node'
            }),
            renderOrder: -1,
            mode: util_graphicGL.Mesh.LINES
        });

        // Mesh used after force directed layout.
        this._edgesMesh = new util_graphicGL.Mesh({
            material: new util_graphicGL.Material({
                shader: util_graphicGL.createShader('ecgl.meshLines2D'),
                transparent: true,
                depthMask: false,
                depthTest: false
            }),
            $ignorePicking: true,
            geometry: new Lines2D({
                useNativeLine: false,
                dynamic: true
            }),
            renderOrder: -1,
            culling: false
        });

        this._layoutId = 0;

        this._control = new util_Roam2DControl({
            zr: api.getZr(),
            viewGL: this.viewGL
        });
        this._control.setTarget(this.groupGL);
        this._control.init();


        this._clickHandler = this._clickHandler.bind(this);
    },

    render: function (seriesModel, ecModel, api) {
        this.groupGL.add(this._pointsBuilder.rootNode);

        this._model = seriesModel;
        this._api = api;

        this._initLayout(seriesModel, ecModel, api);

        this._pointsBuilder.update(seriesModel, ecModel, api);

        if (!(this._forceLayoutInstance instanceof graphGL_ForceAtlas2GPU)) {
            this.groupGL.remove(this._forceEdgesMesh);
        }

        this._updateCamera(seriesModel, api);

        this._control.off('update');
        this._control.on('update', function () {
            api.dispatchAction({
                type: 'graphGLRoam',
                seriesId: seriesModel.id,
                zoom: this._control.getZoom(),
                offset: this._control.getOffset()
            });

            this._pointsBuilder.updateView(this.viewGL.camera);
        }, this);

        this._control.setZoom(util_retrieve.firstNotNull(seriesModel.get('zoom'), 1));
        this._control.setOffset(seriesModel.get('offset') || [0, 0]);

        var mesh = this._pointsBuilder.getPointsMesh();
        mesh.off('mousemove', this._mousemoveHandler);
        mesh.off('mouseout', this._mouseOutHandler, this);
        api.getZr().off('click', this._clickHandler);

        this._pointsBuilder.highlightOnMouseover = true;
        if (seriesModel.get('focusNodeAdjacency')) {
            var focusNodeAdjacencyOn = seriesModel.get('focusNodeAdjacencyOn');
            if (focusNodeAdjacencyOn === 'click') {
                // Remove default emphasis effect
                api.getZr().on('click', this._clickHandler);
            }
            else if (focusNodeAdjacencyOn === 'mouseover') {
                mesh.on('mousemove', this._mousemoveHandler, this);
                mesh.on('mouseout', this._mouseOutHandler, this);

                this._pointsBuilder.highlightOnMouseover = false;
            }
            else {
                if (true) {
                    console.warn('Unkown focusNodeAdjacencyOn value \s' + focusNodeAdjacencyOn);
                }
            }
        }

        // Reset
        this._lastMouseOverDataIndex = -1;
    },

    _clickHandler: function (e) {
        if (this._layouting) {
            return;
        }
        var dataIndex = this._pointsBuilder.getPointsMesh().dataIndex;
        if (dataIndex >= 0) {
            this._api.dispatchAction({
                type: 'graphGLFocusNodeAdjacency',
                seriesId: this._model.id,
                dataIndex: dataIndex
            });
        }
        else {
            this._api.dispatchAction({
                type: 'graphGLUnfocusNodeAdjacency',
                seriesId: this._model.id
            });
        }
    },

    _mousemoveHandler: function (e) {
        if (this._layouting) {
            return;
        }
        var dataIndex = this._pointsBuilder.getPointsMesh().dataIndex;
        if (dataIndex >= 0) {
            if (dataIndex !== this._lastMouseOverDataIndex) {
                this._api.dispatchAction({
                    type: 'graphGLFocusNodeAdjacency',
                    seriesId: this._model.id,
                    dataIndex: dataIndex
                });
            }
        }
        else {
            this._mouseOutHandler(e);
        }

        this._lastMouseOverDataIndex = dataIndex;
    },

    _mouseOutHandler: function (e) {
        if (this._layouting) {
            return;
        }

        this._api.dispatchAction({
            type: 'graphGLUnfocusNodeAdjacency',
            seriesId: this._model.id
        });

        this._lastMouseOverDataIndex = -1;
    },

    _updateForceEdgesGeometry: function (edges, seriesModel) {
        var geometry = this._forceEdgesMesh.geometry;

        var edgeData = seriesModel.getEdgeData();
        var offset = 0;
        var layoutInstance = this._forceLayoutInstance;
        var vertexCount = edgeData.count() * 2;
        geometry.attributes.node.init(vertexCount);
        geometry.attributes.color.init(vertexCount);
        edgeData.each(function (idx) {
            var edge = edges[idx];
            geometry.attributes.node.set(offset, layoutInstance.getNodeUV(edge.node1));
            geometry.attributes.node.set(offset + 1, layoutInstance.getNodeUV(edge.node2));

            var color = getItemVisualColor(edgeData, edge.dataIndex);
            var colorArr = util_graphicGL.parseColor(color);
            colorArr[3] *= util_retrieve.firstNotNull(
                getItemVisualOpacity(edgeData, edge.dataIndex), 1
            );
            geometry.attributes.color.set(offset, colorArr);
            geometry.attributes.color.set(offset + 1, colorArr);

            offset += 2;
        });
        geometry.dirty();
    },

    _updateMeshLinesGeometry: function () {
        var edgeData = this._model.getEdgeData();
        var geometry = this._edgesMesh.geometry;
        var edgeData = this._model.getEdgeData();
        var points = this._model.getData().getLayout('points');

        geometry.resetOffset();
        geometry.setVertexCount(edgeData.count() * geometry.getLineVertexCount());
        geometry.setTriangleCount(edgeData.count() * geometry.getLineTriangleCount());

        var p0 = [];
        var p1 = [];

        var lineWidthQuery = ['lineStyle', 'width'];

        this._originalEdgeColors = new Float32Array(edgeData.count() * 4);
        this._edgeIndicesMap = new Float32Array(edgeData.count());
        edgeData.each(function (idx) {
            var edge = edgeData.graph.getEdgeByIndex(idx);
            var idx1 = edge.node1.dataIndex * 2;
            var idx2 = edge.node2.dataIndex * 2;
            p0[0] = points[idx1];
            p0[1] = points[idx1 + 1];
            p1[0] = points[idx2];
            p1[1] = points[idx2 + 1];

            var color = getItemVisualColor(edgeData, edge.dataIndex);
            var colorArr = util_graphicGL.parseColor(color);
            colorArr[3] *= util_retrieve.firstNotNull(getItemVisualOpacity(edgeData, edge.dataIndex), 1);
            var itemModel = edgeData.getItemModel(edge.dataIndex);
            var lineWidth = util_retrieve.firstNotNull(itemModel.get(lineWidthQuery), 1) * this._api.getDevicePixelRatio();

            geometry.addLine(p0, p1, colorArr, lineWidth);

            for (var k = 0; k < 4; k++) {
                this._originalEdgeColors[edge.dataIndex * 4 + k] = colorArr[k];
            }
            this._edgeIndicesMap[edge.dataIndex] = idx;
        }, this);

        geometry.dirty();
    },

    _updateForceNodesGeometry: function (nodeData) {
        var pointsMesh = this._pointsBuilder.getPointsMesh();
        var pos = [];
        for (var i = 0; i < nodeData.count(); i++) {
            this._forceLayoutInstance.getNodeUV(i, pos);
            pointsMesh.geometry.attributes.position.set(i, pos);
        }
        pointsMesh.geometry.dirty('position');
    },

    _initLayout: function (seriesModel, ecModel, api) {
        var layout = seriesModel.get('layout');
        var graph = seriesModel.getGraph();

        var boxLayoutOption = seriesModel.getBoxLayoutParams();
        var viewport = getLayoutRect(boxLayoutOption, {
            width: api.getWidth(),
            height: api.getHeight()
        });

        if (layout === 'force') {
            if (true) {
                console.warn('Currently only forceAtlas2 layout supported.');
            }
            layout = 'forceAtlas2';
        }
        // Stop previous layout
        this.stopLayout(seriesModel, ecModel, api, {
            beforeLayout: true
        });

        var nodeData = seriesModel.getData();
        var edgeData = seriesModel.getData();
        if (layout === 'forceAtlas2') {
            var layoutModel = seriesModel.getModel('forceAtlas2');
            var layoutInstance = this._forceLayoutInstance;
            var nodes = [];
            var edges = [];

            var nodeDataExtent = nodeData.getDataExtent('value');
            var edgeDataExtent = edgeData.getDataExtent('value');

            var edgeWeightRange = util_retrieve.firstNotNull(layoutModel.get('edgeWeight'), 1.0);
            var nodeWeightRange = util_retrieve.firstNotNull(layoutModel.get('nodeWeight'), 1.0);
            if (typeof edgeWeightRange === 'number') {
                edgeWeightRange = [edgeWeightRange, edgeWeightRange];
            }
            if (typeof nodeWeightRange === 'number') {
                nodeWeightRange = [nodeWeightRange, nodeWeightRange];
            }

            var offset = 0;
            var nodesIndicesMap = {};

            var layoutPoints = new Float32Array(nodeData.count() * 2);
            graph.eachNode(function (node) {
                var dataIndex = node.dataIndex;
                var value = nodeData.get('value', dataIndex);
                var x;
                var y;
                if (nodeData.hasItemOption) {
                    var itemModel = nodeData.getItemModel(dataIndex);
                    x = itemModel.get('x');
                    y = itemModel.get('y');
                }
                if (x == null) {
                    // Random in rectangle
                    x = viewport.x + Math.random() * viewport.width;
                    y = viewport.y + Math.random() * viewport.height;
                }
                layoutPoints[offset * 2] = x;
                layoutPoints[offset * 2 + 1] = y;

                nodesIndicesMap[node.id] = offset++;
                var mass = external_echarts_.number.linearMap(value, nodeDataExtent, nodeWeightRange);
                if (isNaN(mass)) {
                    if (!isNaN(nodeWeightRange[0])) {
                        mass = nodeWeightRange[0];
                    }
                    else {
                        mass = 1;
                    }
                }
                nodes.push({
                    x: x, y: y, mass: mass, size: nodeData.getItemVisual(dataIndex, 'symbolSize')
                });
            });
            nodeData.setLayout('points', layoutPoints);

            graph.eachEdge(function (edge) {
                var dataIndex = edge.dataIndex;
                var value = nodeData.get('value', dataIndex);
                var weight = external_echarts_.number.linearMap(value, edgeDataExtent, edgeWeightRange);
                if (isNaN(weight)) {
                    if (!isNaN(edgeWeightRange[0])) {
                        weight = edgeWeightRange[0];
                    }
                    else {
                        weight = 1;
                    }
                }
                edges.push({
                    node1: nodesIndicesMap[edge.node1.id],
                    node2: nodesIndicesMap[edge.node2.id],
                    weight: weight,
                    dataIndex: dataIndex
                });
            });
            if (!layoutInstance) {
                var isGPU = layoutModel.get('GPU');
                if (this._forceLayoutInstance) {
                    if ((isGPU && !(this._forceLayoutInstance instanceof graphGL_ForceAtlas2GPU))
                        || (!isGPU && !(this._forceLayoutInstance instanceof graphGL_ForceAtlas2))
                    ) {
                        // Mark to dispose
                        this._forceLayoutInstanceToDispose = this._forceLayoutInstance;
                    }
                }
                layoutInstance = this._forceLayoutInstance = isGPU
                    ? new graphGL_ForceAtlas2GPU()
                    : new graphGL_ForceAtlas2();
            }
            layoutInstance.initData(nodes, edges);
            layoutInstance.updateOption(layoutModel.option);

            // Update lines geometry after first layout;
            this._updateForceEdgesGeometry(layoutInstance.getEdges(), seriesModel);
            this._updatePositionTexture();

            api.dispatchAction({
                type: 'graphGLStartLayout',
                from: this.uid
            });
        }
        else {
            var layoutPoints = new Float32Array(nodeData.count() * 2);
            var offset = 0;
            graph.eachNode(function (node) {
                var dataIndex = node.dataIndex;
                var x;
                var y;
                if (nodeData.hasItemOption) {
                    var itemModel = nodeData.getItemModel(dataIndex);
                    x = itemModel.get('x');
                    y = itemModel.get('y');
                }
                layoutPoints[offset++] = x;
                layoutPoints[offset++] = y;
            });
            nodeData.setLayout('points', layoutPoints);

            this._updateAfterLayout(seriesModel, ecModel, api);
        }
    },

    _updatePositionTexture: function () {
        var positionTex = this._forceLayoutInstance.getNodePositionTexture();
        this._pointsBuilder.setPositionTexture(positionTex);
        this._forceEdgesMesh.material.set('positionTex', positionTex);
    },

    startLayout: function (seriesModel, ecModel, api, payload) {
        if (payload && payload.from != null && payload.from !== this.uid) {
            return;
        }

        var viewGL = this.viewGL;
        var api = this._api;
        var layoutInstance = this._forceLayoutInstance;
        var data = this._model.getData();
        var layoutModel = this._model.getModel('forceAtlas2');

        if (!layoutInstance) {
            if (true) {
                console.error('None layout don\'t have startLayout action');
            }
            return;
        }

        this.groupGL.remove(this._edgesMesh);
        this.groupGL.add(this._forceEdgesMesh);

        if (!this._forceLayoutInstance) {
            return;
        }

        this._updateForceNodesGeometry(seriesModel.getData());
        this._pointsBuilder.hideLabels();

        var self = this;
        var layoutId = this._layoutId = globalLayoutId++;
        var maxSteps = layoutModel.getShallow('maxSteps');
        var steps = layoutModel.getShallow('steps');
        var stepsCount = 0;
        var syncStepCount = Math.max(steps * 2, 20);
        var doLayout = function (layoutId) {
            if (layoutId !== self._layoutId) {
                return;
            }
            if (layoutInstance.isFinished(maxSteps)) {
                api.dispatchAction({
                    type: 'graphGLStopLayout',
                    from: self.uid
                });
                api.dispatchAction({
                    type: 'graphGLFinishLayout',
                    points: data.getLayout('points'),
                    from: self.uid
                });
                return;
            }

            layoutInstance.update(viewGL.layer.renderer, steps, function () {
                self._updatePositionTexture();
                // PENDING Performance.
                stepsCount += steps;
                // Sync posiiton every 20 steps.
                if (stepsCount >= syncStepCount) {
                    self._syncNodePosition(seriesModel);
                    stepsCount = 0;
                }
                // Position texture will been swapped. set every time.
                api.getZr().refresh();

                animation_requestAnimationFrame(function () {
                    doLayout(layoutId);
                });
            });
        };

        animation_requestAnimationFrame(function () {
            if (self._forceLayoutInstanceToDispose) {
                self._forceLayoutInstanceToDispose.dispose(viewGL.layer.renderer);
                self._forceLayoutInstanceToDispose = null;
            }
            doLayout(layoutId);
        });

        this._layouting = true;
    },

    stopLayout: function (seriesModel, ecModel, api, payload) {
        if (payload && payload.from != null && payload.from !== this.uid) {
            return;
        }

        this._layoutId = 0;
        this.groupGL.remove(this._forceEdgesMesh);
        this.groupGL.add(this._edgesMesh);

        if (!this._forceLayoutInstance) {
            return;
        }

        if (!this.viewGL.layer) {
            return;
        }

        if (!(payload && payload.beforeLayout)) {
            this._syncNodePosition(seriesModel);
            this._updateAfterLayout(seriesModel, ecModel, api);
        }

        this._api.getZr().refresh();

        this._layouting = false;
    },

    _syncNodePosition: function (seriesModel) {
        var points = this._forceLayoutInstance.getNodePosition(this.viewGL.layer.renderer);
        seriesModel.getData().setLayout('points', points);

        seriesModel.setNodePosition(points);
    },

    _updateAfterLayout: function (seriesModel, ecModel, api) {
        this._updateMeshLinesGeometry();

        this._pointsBuilder.removePositionTexture();

        this._pointsBuilder.updateLayout(seriesModel, ecModel, api);

        this._pointsBuilder.updateView(this.viewGL.camera);

        this._pointsBuilder.updateLabels();

        this._pointsBuilder.showLabels();

    },

    focusNodeAdjacency: function (seriesModel, ecModel, api, payload) {

        var data = this._model.getData();

        this._downplayAll();

        var dataIndex = payload.dataIndex;

        var graph = data.graph;

        var focusNodes = [];
        var node = graph.getNodeByIndex(dataIndex);
        focusNodes.push(node);
        node.edges.forEach(function (edge) {
            if (edge.dataIndex < 0) {
                return;
            }
            edge.node1 !== node && focusNodes.push(edge.node1);
            edge.node2 !== node && focusNodes.push(edge.node2);
        }, this);

        this._pointsBuilder.fadeOutAll(0.05);
        this._fadeOutEdgesAll(0.05);

        focusNodes.forEach(function (node) {
            this._pointsBuilder.highlight(data, node.dataIndex);
        }, this);

        this._pointsBuilder.updateLabels(focusNodes.map(function (node) {
            return node.dataIndex;
        }));

        var focusEdges = [];
        node.edges.forEach(function (edge) {
            if (edge.dataIndex >= 0) {
                this._highlightEdge(edge.dataIndex);
                focusEdges.push(edge);
            }
        }, this);

        this._focusNodes = focusNodes;
        this._focusEdges = focusEdges;
    },

    unfocusNodeAdjacency: function (seriesModel, ecModel, api, payload) {

        this._downplayAll();

        this._pointsBuilder.fadeInAll();
        this._fadeInEdgesAll();

        this._pointsBuilder.updateLabels();
    },

    _highlightEdge: function (dataIndex) {
        var itemModel = this._model.getEdgeData().getItemModel(dataIndex);
        var emphasisColor =  util_graphicGL.parseColor(itemModel.get('emphasis.lineStyle.color') || itemModel.get('lineStyle.color'));
        var emphasisOpacity = util_retrieve.firstNotNull(itemModel.get('emphasis.lineStyle.opacity'), itemModel.get('lineStyle.opacity'), 1);
        emphasisColor[3] *= emphasisOpacity;

        this._edgesMesh.geometry.setItemColor(this._edgeIndicesMap[dataIndex], emphasisColor);
    },

    _downplayAll: function () {
        if (this._focusNodes) {
            this._focusNodes.forEach(function (node) {
                this._pointsBuilder.downplay(this._model.getData(), node.dataIndex);
            }, this);
        }
        if (this._focusEdges) {
            this._focusEdges.forEach(function (edge) {
                this._downplayEdge(edge.dataIndex);
            }, this);
        }
    },

    _downplayEdge: function (dataIndex) {
        var color = this._getColor(dataIndex, []);
        this._edgesMesh.geometry.setItemColor(this._edgeIndicesMap[dataIndex], color);
    },

    _setEdgeFade: (function () {
        var color = [];
        return function (dataIndex, percent) {
            this._getColor(dataIndex, color);
            color[3] *= percent;
            this._edgesMesh.geometry.setItemColor(this._edgeIndicesMap[dataIndex], color);
        };
    })(),

    _getColor: function (dataIndex, out) {
        for (var i = 0; i < 4; i++) {
            out[i] = this._originalEdgeColors[dataIndex * 4 + i];
        }
        return out;
    },

    _fadeOutEdgesAll: function (percent) {
        var graph = this._model.getData().graph;

        graph.eachEdge(function (edge) {
            this._setEdgeFade(edge.dataIndex, percent);
        }, this);
    },

    _fadeInEdgesAll: function () {
        this._fadeOutEdgesAll(1);
    },

    _updateCamera: function (seriesModel, api) {
        this.viewGL.setViewport(0, 0, api.getWidth(), api.getHeight(), api.getDevicePixelRatio());
        var camera = this.viewGL.camera;
        var nodeData = seriesModel.getData();
        var points = nodeData.getLayout('points');
        var min = GraphGLView_vec2.create(Infinity, Infinity);
        var max = GraphGLView_vec2.create(-Infinity, -Infinity);
        var pt = [];
        for (var i = 0; i < points.length;) {
            pt[0] = points[i++];
            pt[1] = points[i++];
            GraphGLView_vec2.min(min, min, pt);
            GraphGLView_vec2.max(max, max, pt);
        }
        var cy = (max[1] + min[1]) / 2;
        var cx = (max[0] + min[0]) / 2;
        // Only fit the camera when graph is not in the center.
        // PENDING
        if (cx > camera.left && cx < camera.right
            && cy < camera.bottom && cy > camera.top
        ) {
            return;
        }

        // Scale a bit
        var width = Math.max(max[0] - min[0], 10);
        // Keep aspect
        var height = width / api.getWidth() * api.getHeight();
        width *= 1.4;
        height *= 1.4;
        min[0] -= width * 0.2;

        camera.left = min[0];
        camera.top = cy - height / 2;
        camera.bottom = cy + height / 2;
        camera.right = width + min[0];
        camera.near = 0;
        camera.far = 100;
    },

    dispose: function () {
        var renderer = this.viewGL.layer.renderer;
        if (this._forceLayoutInstance) {
            this._forceLayoutInstance.dispose(renderer);
        }
        this.groupGL.removeAll();

        // Stop layout.
        this._layoutId = -1;

        this._pointsBuilder.dispose();
    },

    remove: function () {
        this.groupGL.removeAll();
        this._control.dispose();
    }
}));
;// CONCATENATED MODULE: ./src/chart/graphGL/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.







function install_normalize(a) {
    if (!(a instanceof Array)) {
        a = [a, a];
    }
    return a;
}
function graphGL_install_install(registers) {

    registers.registerChartView(GraphGLView);
    registers.registerSeriesModel(GraphGLSeries);

    registers.registerVisual(function (ecModel) {
        const paletteScope = {};
        ecModel.eachSeriesByType('graphGL', function (seriesModel) {
            var categoriesData = seriesModel.getCategoriesData();
            var data = seriesModel.getData();

            var categoryNameIdxMap = {};

            categoriesData.each(function (idx) {
                var name = categoriesData.getName(idx);
                // Add prefix to avoid conflict with Object.prototype.
                categoryNameIdxMap['ec-' + name] = idx;
                var itemModel = categoriesData.getItemModel(idx);

                var style = itemModel.getModel('itemStyle').getItemStyle();
                if (!style.fill) {
                    // Get color from palette.
                    style.fill = seriesModel.getColorFromPalette(name, paletteScope);
                }
                categoriesData.setItemVisual(idx, 'style', style);

                var symbolVisualList = ['symbol', 'symbolSize', 'symbolKeepAspect'];

                for (let i = 0; i < symbolVisualList.length; i++) {
                    var symbolVisual = itemModel.getShallow(symbolVisualList[i], true);
                    if (symbolVisual != null) {
                        categoriesData.setItemVisual(idx, symbolVisualList[i], symbolVisual);
                    }
                }
            });

            // Assign category color to visual
            if (categoriesData.count()) {
                data.each(function (idx) {
                    var model = data.getItemModel(idx);
                    let categoryIdx = model.getShallow('category');
                    if (categoryIdx != null) {
                        if (typeof categoryIdx === 'string') {
                            categoryIdx = categoryNameIdxMap['ec-' + categoryIdx];
                        }

                        var categoryStyle = categoriesData.getItemVisual(categoryIdx, 'style');
                        var style = data.ensureUniqueItemVisual(idx, 'style');
                        external_echarts_.util.extend(style, categoryStyle);

                        var visualList = ['symbol', 'symbolSize', 'symbolKeepAspect'];

                        for (let i = 0; i < visualList.length; i++) {
                            data.setItemVisual(
                                idx, visualList[i],
                                categoriesData.getItemVisual(categoryIdx, visualList[i])
                            );
                        }
                    }
                });
            }
        });
    });

    registers.registerVisual(function (ecModel) {

        ecModel.eachSeriesByType('graphGL', function (seriesModel) {
            var graph = seriesModel.getGraph();
            var edgeData = seriesModel.getEdgeData();
            var symbolType = install_normalize(seriesModel.get('edgeSymbol'));
            var symbolSize = install_normalize(seriesModel.get('edgeSymbolSize'));

            edgeData.setVisual('drawType', 'stroke');

            // var colorQuery = ['lineStyle', 'color'];
            // var opacityQuery = ['lineStyle', 'opacity'];

            edgeData.setVisual('fromSymbol', symbolType && symbolType[0]);
            edgeData.setVisual('toSymbol', symbolType && symbolType[1]);
            edgeData.setVisual('fromSymbolSize', symbolSize && symbolSize[0]);
            edgeData.setVisual('toSymbolSize', symbolSize && symbolSize[1]);

            edgeData.setVisual('style', seriesModel.getModel('lineStyle').getLineStyle());

            edgeData.each(function (idx) {
                var itemModel = edgeData.getItemModel(idx);
                var edge = graph.getEdgeByIndex(idx);
                var symbolType = install_normalize(itemModel.getShallow('symbol', true));
                var symbolSize = install_normalize(itemModel.getShallow('symbolSize', true));
                // Edge visual must after node visual
                var style = itemModel.getModel('lineStyle').getLineStyle();

                var existsStyle = edgeData.ensureUniqueItemVisual(idx, 'style');
                external_echarts_.util.extend(existsStyle, style);

                switch (existsStyle.stroke) {
                    case 'source': {
                        var nodeStyle = edge.node1.getVisual('style');
                        existsStyle.stroke = nodeStyle && nodeStyle.fill;
                        break;
                    }
                    case 'target': {
                        var nodeStyle = edge.node2.getVisual('style');
                        existsStyle.stroke = nodeStyle && nodeStyle.fill;
                        break;
                    }
                }

                symbolType[0] && edge.setVisual('fromSymbol', symbolType[0]);
                symbolType[1] && edge.setVisual('toSymbol', symbolType[1]);
                symbolSize[0] && edge.setVisual('fromSymbolSize', symbolSize[0]);
                symbolSize[1] && edge.setVisual('toSymbolSize', symbolSize[1]);
            });
        });
    });

    registers.registerAction({
        type: 'graphGLRoam',
        event: 'graphglroam',
        update: 'series.graphGL:roam'
    }, function (payload, ecModel) {
        ecModel.eachComponent({
            mainType: 'series', query: payload
        }, function (componentModel) {
            componentModel.setView(payload);
        });
    });

    function noop() {}

    registers.registerAction({
        type: 'graphGLStartLayout',
        event: 'graphgllayoutstarted',
        update: 'series.graphGL:startLayout'
    }, noop);

    registers.registerAction({
        type: 'graphGLStopLayout',
        event: 'graphgllayoutstopped',
        update: 'series.graphGL:stopLayout'
    }, noop);

    registers.registerAction({
        type: 'graphGLFocusNodeAdjacency',
        event: 'graphGLFocusNodeAdjacency',
        update: 'series.graphGL:focusNodeAdjacency'
    }, noop);


    registers.registerAction({
        type: 'graphGLUnfocusNodeAdjacency',
        event: 'graphGLUnfocusNodeAdjacency',
        update: 'series.graphGL:unfocusNodeAdjacency'
    }, noop);
}
;// CONCATENATED MODULE: ./src/chart/graphGL.js


(0,external_echarts_.use)(graphGL_install_install);
;// CONCATENATED MODULE: ./src/chart/flowGL/FlowGLSeries.js


/* harmony default export */ const FlowGLSeries = (external_echarts_.SeriesModel.extend({

    type: 'series.flowGL',

    dependencies: ['geo', 'grid', 'bmap'],

    visualStyleAccessPath: 'itemStyle',

    getInitialData: function (option, ecModel) {
        var coordType = this.get('coordinateSystem');
        // TODO hotfix for the bug in echarts that get coord dimensions is undefined.
        var coordSysDimensions = coordType === 'geo' ? ['lng', 'lat']
            : (external_echarts_.getCoordinateSystemDimensions(coordType) || ['x', 'y']);
        if (true) {
            if (coordSysDimensions.length > 2) {
                throw new Error('flowGL can only be used on 2d coordinate systems.');
            }
        }
        coordSysDimensions.push('vx', 'vy');
        var dimensions = external_echarts_.helper.createDimensions(this.getSource(), {
            coordDimensions: coordSysDimensions,
            encodeDefine: this.get('encode'),
            dimensionsDefine: this.get('dimensions')
        });
        var data = new external_echarts_.List(dimensions, this);
        data.initData(this.getSource());
        return data;
    },

    defaultOption: {
        coordinateSystem: 'cartesian2d',
        zlevel: 10,

        supersampling: 1,
        // 128x128 particles
        particleType: 'point',

        particleDensity: 128,
        particleSize: 1,
        particleSpeed: 1,

        particleTrail: 2,

        colorTexture: null,

        gridWidth: 'auto',
        gridHeight: 'auto',

        itemStyle: {
            color: '#fff',
            opacity: 0.8
        }
    }
}));
;// CONCATENATED MODULE: ./src/chart/flowGL/Line2D.js
/**
 * Lines geometry
 * Use screen space projected lines lineWidth > MAX_LINE_WIDTH
 * https://mattdesl.svbtle.com/drawing-lines-is-hard
 * @module echarts-gl/util/geometry/LinesGeometry
 * @author Yi Shen(http://github.com/pissang)
 */




/**
 * @constructor
 * @alias module:echarts-gl/chart/flowGL/Line2D
 * @extends clay.Geometry
 */

var Line2D_LinesGeometry = src_Geometry.extend(function () {
    return {

        dynamic: true,

        attributes: {
            position: new src_Geometry.Attribute('position', 'float', 3, 'POSITION')
        }
    };
},
/** @lends module: echarts-gl/util/geometry/LinesGeometry.prototype */
{

    /**
     * Reset offset
     */
    resetOffset: function () {
        this._vertexOffset = 0;
        this._faceOffset = 0;
    },

    /**
     * @param {number} nVertex
     */
    setLineCount: function (nLine) {
        var attributes = this.attributes;
        var nVertex = 4 * nLine;
        var nTriangle = 2 * nLine;
        if (this.vertexCount !== nVertex) {
            attributes.position.init(nVertex);
        }
        if (this.triangleCount !== nTriangle) {
            if (nTriangle === 0) {
                this.indices = null;
            }
            else {
                this.indices = this.vertexCount > 0xffff ? new Uint32Array(nTriangle * 3) : new Uint16Array(nTriangle * 3);
            }
        }
    },

    addLine: function (p) {
        var vertexOffset = this._vertexOffset;
        this.attributes.position.set(vertexOffset, [p[0], p[1], 1]);
        this.attributes.position.set(vertexOffset + 1, [p[0], p[1], -1]);
        this.attributes.position.set(vertexOffset + 2, [p[0], p[1], 2]);
        this.attributes.position.set(vertexOffset + 3, [p[0], p[1], -2]);

        this.setTriangleIndices(
            this._faceOffset++, [
                vertexOffset, vertexOffset + 1, vertexOffset + 2
            ]
        );
        this.setTriangleIndices(
            this._faceOffset++, [
                vertexOffset + 1, vertexOffset + 2, vertexOffset + 3
            ]
        );

        this._vertexOffset += 4;
    }
});

/* harmony default export */ const Line2D = (Line2D_LinesGeometry);
;// CONCATENATED MODULE: ./src/chart/flowGL/vectorFieldParticle.glsl.js
/* harmony default export */ const vectorFieldParticle_glsl = ("@export ecgl.vfParticle.particle.fragment\n\nuniform sampler2D particleTexture;\nuniform sampler2D spawnTexture;\nuniform sampler2D velocityTexture;\n\nuniform float deltaTime;\nuniform float elapsedTime;\n\nuniform float speedScaling : 1.0;\n\nuniform vec2 textureSize;\nuniform vec4 region : [0, 0, 1, 1];\nuniform float firstFrameTime;\n\nvarying vec2 v_Texcoord;\n\n\nvoid main()\n{\n vec4 p = texture2D(particleTexture, v_Texcoord);\n bool spawn = false;\n if (p.w <= 0.0) {\n p = texture2D(spawnTexture, fract(v_Texcoord + elapsedTime / 10.0));\n p.w -= firstFrameTime;\n spawn = true;\n }\n vec2 v = texture2D(velocityTexture, fract(p.xy * region.zw + region.xy)).xy;\n v = (v - 0.5) * 2.0;\n p.z = length(v);\n p.xy += v * deltaTime / 10.0 * speedScaling;\n p.w -= deltaTime;\n\n if (spawn || p.xy != fract(p.xy)) {\n p.z = 0.0;\n }\n p.xy = fract(p.xy);\n\n gl_FragColor = p;\n}\n@end\n\n@export ecgl.vfParticle.renderPoints.vertex\n\n#define PI 3.1415926\n\nattribute vec2 texcoord : TEXCOORD_0;\n\nuniform sampler2D particleTexture;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nuniform float size : 1.0;\n\nvarying float v_Mag;\nvarying vec2 v_Uv;\n\nvoid main()\n{\n vec4 p = texture2D(particleTexture, texcoord);\n\n if (p.w > 0.0 && p.z > 1e-5) {\n gl_Position = worldViewProjection * vec4(p.xy * 2.0 - 1.0, 0.0, 1.0);\n }\n else {\n gl_Position = vec4(100000.0, 100000.0, 100000.0, 1.0);\n }\n\n v_Mag = p.z;\n v_Uv = p.xy;\n\n gl_PointSize = size;\n}\n\n@end\n\n@export ecgl.vfParticle.renderPoints.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform sampler2D gradientTexture;\nuniform sampler2D colorTexture;\nuniform sampler2D spriteTexture;\n\nvarying float v_Mag;\nvarying vec2 v_Uv;\n\nvoid main()\n{\n gl_FragColor = color;\n#ifdef SPRITETEXTURE_ENABLED\n gl_FragColor *= texture2D(spriteTexture, gl_PointCoord);\n if (color.a == 0.0) {\n discard;\n }\n#endif\n#ifdef GRADIENTTEXTURE_ENABLED\n gl_FragColor *= texture2D(gradientTexture, vec2(v_Mag, 0.5));\n#endif\n#ifdef COLORTEXTURE_ENABLED\n gl_FragColor *= texture2D(colorTexture, v_Uv);\n#endif\n}\n\n@end\n\n@export ecgl.vfParticle.renderLines.vertex\n\n#define PI 3.1415926\n\nattribute vec3 position : POSITION;\n\nuniform sampler2D particleTexture;\nuniform sampler2D prevParticleTexture;\n\nuniform float size : 1.0;\nuniform vec4 vp: VIEWPORT;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\n\nvarying float v_Mag;\nvarying vec2 v_Uv;\n\n@import clay.util.rand\n\nvoid main()\n{\n vec4 p = texture2D(particleTexture, position.xy);\n vec4 p2 = texture2D(prevParticleTexture, position.xy);\n\n p.xy = p.xy * 2.0 - 1.0;\n p2.xy = p2.xy * 2.0 - 1.0;\n\n if (p.w > 0.0 && p.z > 1e-5) {\n vec2 dir = normalize(p.xy - p2.xy);\n vec2 norm = vec2(dir.y / vp.z, -dir.x / vp.w) * sign(position.z) * size;\n if (abs(position.z) == 2.0) {\n gl_Position = vec4(p.xy + norm, 0.0, 1.0);\n v_Uv = p.xy;\n v_Mag = p.z;\n }\n else {\n gl_Position = vec4(p2.xy + norm, 0.0, 1.0);\n v_Mag = p2.z;\n v_Uv = p2.xy;\n }\n gl_Position = worldViewProjection * gl_Position;\n }\n else {\n gl_Position = vec4(100000.0, 100000.0, 100000.0, 1.0);\n }\n}\n\n@end\n\n@export ecgl.vfParticle.renderLines.fragment\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform sampler2D gradientTexture;\nuniform sampler2D colorTexture;\n\nvarying float v_Mag;\nvarying vec2 v_Uv;\n\nvoid main()\n{\n gl_FragColor = color;\n #ifdef GRADIENTTEXTURE_ENABLED\n gl_FragColor *= texture2D(gradientTexture, vec2(v_Mag, 0.5));\n#endif\n#ifdef COLORTEXTURE_ENABLED\n gl_FragColor *= texture2D(colorTexture, v_Uv);\n#endif\n}\n\n@end\n");

;// CONCATENATED MODULE: ./src/chart/flowGL/VectorFieldParticleSurface.js












// import TemporalSS from '../../effect/TemporalSuperSampling';



src_Shader.import(vectorFieldParticle_glsl);

function createSpriteCanvas(size) {
    var canvas = document.createElement('canvas');
    canvas.width = canvas.height = size;
    var ctx = canvas.getContext('2d');
    ctx.fillStyle = '#fff';
    ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2);
    ctx.fill();
    return canvas;
}

// import spriteUtil from '../../util/sprite';

var VectorFieldParticleSurface = function () {

    /**
     * @type {number}
     */
    this.motionBlurFactor = 0.99;
    /**
     * Vector field lookup image
     * @type {clay.Texture2D}
     */
    this.vectorFieldTexture = new src_Texture2D({
        type: src_Texture.FLOAT,
        // minFilter: Texture.NEAREST,
        // magFilter: Texture.NEAREST,
        flipY: false
    });

    /**
     * Particle life range
     * @type {Array.<number>}
     */
    this.particleLife = [5, 20];

    this._particleType = 'point';

    /**
     * @type {number}
     */
    this._particleSize = 1;

    /**
     * @type {Array.<number>}
     */
    this.particleColor = [1, 1, 1, 1];

    /**
     * @type {number}
     */
    this.particleSpeedScaling = 1.0;

    /**
     * @type {clay.Texture2D}
     */
    this._thisFrameTexture = null;

    this._particlePass = null;
    this._spawnTexture = null;
    this._particleTexture0 = null;
    this._particleTexture1 = null;

    this._particlePointsMesh = null;

    this._surfaceFrameBuffer = null;

    this._elapsedTime = 0.0;

    this._scene = null;
    this._camera = null;

    this._lastFrameTexture = null;

    // this._temporalSS = new TemporalSS(50);

    // this._antialising = false;

    this._supersampling = 1;

    this._downsampleTextures = [];

    this._width = 512;
    this._height = 512;

    this.init();
};

VectorFieldParticleSurface.prototype = {

    constructor: VectorFieldParticleSurface,

    init: function () {
        var parameters = {
            type: src_Texture.FLOAT,
            minFilter: src_Texture.NEAREST,
            magFilter: src_Texture.NEAREST,
            useMipmap: false
        };
        this._spawnTexture = new src_Texture2D(parameters);

        this._particleTexture0 = new src_Texture2D(parameters);
        this._particleTexture1 = new src_Texture2D(parameters);

        this._frameBuffer = new src_FrameBuffer({
            depthBuffer: false
        });
        this._particlePass = new compositor_Pass({
            fragment: src_Shader.source('ecgl.vfParticle.particle.fragment')
        });
        this._particlePass.setUniform('velocityTexture', this.vectorFieldTexture);
        this._particlePass.setUniform('spawnTexture', this._spawnTexture);

        this._downsamplePass = new compositor_Pass({
            fragment: src_Shader.source('clay.compositor.downsample')
        });

        var particlePointsMesh = new src_Mesh({
            // Render after last frame full quad
            renderOrder: 10,
            material: new src_Material({
                shader: new src_Shader(
                    src_Shader.source('ecgl.vfParticle.renderPoints.vertex'),
                    src_Shader.source('ecgl.vfParticle.renderPoints.fragment')
                )
            }),
            mode: src_Mesh.POINTS,
            geometry: new src_Geometry({
                dynamic: true,
                mainAttribute: 'texcoord0'
            })
        });
        var particleLinesMesh = new src_Mesh({
            // Render after last frame full quad
            renderOrder: 10,
            material: new src_Material({
                shader: new src_Shader(
                    src_Shader.source('ecgl.vfParticle.renderLines.vertex'),
                    src_Shader.source('ecgl.vfParticle.renderLines.fragment')
                )
            }),
            geometry: new Line2D(),
            culling: false
        });
        var lastFrameFullQuad = new src_Mesh({
            material: new src_Material({
                shader: new src_Shader(
                    src_Shader.source('ecgl.color.vertex'),
                    src_Shader.source('ecgl.color.fragment')
                )
                // DO NOT BLEND Blend will multiply alpha
                // transparent: true
            }),
            geometry: new geometry_Plane()
        });
        lastFrameFullQuad.material.enableTexture('diffuseMap');

        this._particlePointsMesh = particlePointsMesh;
        this._particleLinesMesh = particleLinesMesh;
        this._lastFrameFullQuadMesh = lastFrameFullQuad;

        this._camera = new camera_Orthographic();
        this._thisFrameTexture = new src_Texture2D();
        this._lastFrameTexture = new src_Texture2D();
    },

    setParticleDensity: function (width, height) {
        var nVertex = width * height;

        var spawnTextureData = new Float32Array(nVertex * 4);
        var off = 0;
        var lifeRange = this.particleLife;
        for (var i = 0; i < width; i++) {
            for (var j = 0; j < height; j++, off++) {
                // x position, range [0 - 1]
                spawnTextureData[off * 4] = Math.random();
                // y position, range [0 - 1]
                spawnTextureData[off * 4 + 1] = Math.random();
                // Some property
                spawnTextureData[off * 4 + 2] = Math.random();
                var life = (lifeRange[1] - lifeRange[0]) * Math.random() + lifeRange[0];
                // Particle life
                spawnTextureData[off * 4 + 3] = life;
            }
        }

        if (this._particleType === 'line') {
            this._setLineGeometry(width, height);
        }
        else {
            this._setPointsGeometry(width, height);
        }

        this._spawnTexture.width = width;
        this._spawnTexture.height = height;
        this._spawnTexture.pixels = spawnTextureData;

        this._particleTexture0.width = this._particleTexture1.width = width;
        this._particleTexture0.height = this._particleTexture1.height = height;

        this._particlePass.setUniform('textureSize', [width, height]);
    },

    _setPointsGeometry: function (width, height) {
        var nVertex = width * height;
        var geometry = this._particlePointsMesh.geometry;
        var attributes = geometry.attributes;
        attributes.texcoord0.init(nVertex);

        var off = 0;
        for (var i = 0; i < width; i++) {
            for (var j = 0; j < height; j++, off++) {
                attributes.texcoord0.value[off * 2] = i / width;
                attributes.texcoord0.value[off * 2 + 1] = j / height;
            }
        }
        geometry.dirty();
    },

    _setLineGeometry: function (width, height) {
        var nLine = width * height;
        var geometry = this._getParticleMesh().geometry;
        geometry.setLineCount(nLine);
        geometry.resetOffset();
        for (var i = 0; i < width; i++) {
            for (var j = 0; j < height; j++) {
                geometry.addLine([i / width, j / height]);
            }
        }
        geometry.dirty();
    },

    _getParticleMesh: function () {
        return this._particleType === 'line' ? this._particleLinesMesh : this._particlePointsMesh;
    },

    update: function (renderer, api, deltaTime, firstFrame) {
        var particleMesh = this._getParticleMesh();
        var frameBuffer = this._frameBuffer;
        var particlePass = this._particlePass;

        if (firstFrame) {
            this._updateDownsampleTextures(renderer, api);
        }

        particleMesh.material.set('size', this._particleSize * this._supersampling);
        particleMesh.material.set('color', this.particleColor);
        particlePass.setUniform('speedScaling', this.particleSpeedScaling);

        frameBuffer.attach(this._particleTexture1);
        particlePass.setUniform('firstFrameTime', firstFrame ? (this.particleLife[1] + this.particleLife[0]) / 2 : 0);
        particlePass.setUniform('particleTexture', this._particleTexture0);
        particlePass.setUniform('deltaTime', deltaTime);
        particlePass.setUniform('elapsedTime', this._elapsedTime);
        particlePass.render(renderer, frameBuffer);

        particleMesh.material.set('particleTexture', this._particleTexture1);
        particleMesh.material.set('prevParticleTexture', this._particleTexture0);

        frameBuffer.attach(this._thisFrameTexture);
        frameBuffer.bind(renderer);
        renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT);
        var lastFrameFullQuad = this._lastFrameFullQuadMesh;
        lastFrameFullQuad.material.set('diffuseMap', this._lastFrameTexture);
        lastFrameFullQuad.material.set('color', [1, 1, 1, this.motionBlurFactor]);

        this._camera.update(true);
        renderer.renderPass([lastFrameFullQuad, particleMesh], this._camera);
        frameBuffer.unbind(renderer);

        this._downsample(renderer);

        this._swapTexture();

        this._elapsedTime += deltaTime;
    },

    _downsample: function (renderer) {
        var downsampleTextures = this._downsampleTextures;
        if (downsampleTextures.length === 0) {
            return;
        }
        var current = 0;
        var sourceTexture = this._thisFrameTexture;
        var targetTexture = downsampleTextures[current];

        while (targetTexture) {
            this._frameBuffer.attach(targetTexture);
            this._downsamplePass.setUniform('texture', sourceTexture);
            this._downsamplePass.setUniform('textureSize', [sourceTexture.width, sourceTexture.height]);
            this._downsamplePass.render(renderer, this._frameBuffer);

            sourceTexture = targetTexture;
            targetTexture = downsampleTextures[++current];
        }
    },

    getSurfaceTexture: function () {
        var downsampleTextures = this._downsampleTextures;
        return downsampleTextures.length > 0
            ? downsampleTextures[downsampleTextures.length - 1]
            : this._lastFrameTexture;
    },

    setRegion: function (region) {
        this._particlePass.setUniform('region', region);
    },

    resize: function (width, height) {
        this._lastFrameTexture.width = width * this._supersampling;
        this._lastFrameTexture.height = height * this._supersampling;
        this._thisFrameTexture.width = width * this._supersampling;
        this._thisFrameTexture.height = height * this._supersampling;

        this._width = width;
        this._height = height;
    },

    setParticleSize: function (size) {
        var particleMesh = this._getParticleMesh();
        if (size <= 2) {
            particleMesh.material.disableTexture('spriteTexture');
            particleMesh.material.transparent = false;
            return;
        }
        if (!this._spriteTexture) {
            this._spriteTexture = new src_Texture2D();
        }
        if (!this._spriteTexture.image || this._spriteTexture.image.width !== size) {
            this._spriteTexture.image = createSpriteCanvas(size);
            this._spriteTexture.dirty();
        }
        particleMesh.material.transparent = true;
        particleMesh.material.enableTexture('spriteTexture');
        particleMesh.material.set('spriteTexture', this._spriteTexture);

        this._particleSize = size;
    },

    setGradientTexture: function (gradientTexture) {
        var material = this._getParticleMesh().material;
        material[gradientTexture ? 'enableTexture' : 'disableTexture']('gradientTexture');
        material.setUniform('gradientTexture', gradientTexture);
    },

    setColorTextureImage: function (colorTextureImg, api) {
        var material = this._getParticleMesh().material;
        material.setTextureImage('colorTexture', colorTextureImg, api, {
            flipY: true
        });
    },

    setParticleType: function (type) {
        this._particleType = type;
    },

    clearFrame: function (renderer) {
        var frameBuffer = this._frameBuffer;
        frameBuffer.attach(this._lastFrameTexture);
        frameBuffer.bind(renderer);
        renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT);
        frameBuffer.unbind(renderer);
    },

    setSupersampling: function (supersampling) {
        this._supersampling = supersampling;
        this.resize(this._width, this._height);
    },

    _updateDownsampleTextures: function (renderer, api) {
        var downsampleTextures = this._downsampleTextures;
        var upScale = Math.max(Math.floor(Math.log(this._supersampling / api.getDevicePixelRatio()) / Math.log(2)), 0);
        var scale = 2;
        var width = this._width * this._supersampling;
        var height = this._height * this._supersampling;
        for (var i = 0; i < upScale; i++) {
            downsampleTextures[i] = downsampleTextures[i] || new src_Texture2D();
            downsampleTextures[i].width = width / scale;
            downsampleTextures[i].height = height / scale;
            scale *= 2;
        }
        for (;i < downsampleTextures.length; i++) {
            downsampleTextures[i].dispose(renderer);
        }
        downsampleTextures.length = upScale;
    },

    _swapTexture: function () {
        var tmp = this._particleTexture0;
        this._particleTexture0 = this._particleTexture1;
        this._particleTexture1 = tmp;

        var tmp = this._thisFrameTexture;
        this._thisFrameTexture = this._lastFrameTexture;
        this._lastFrameTexture = tmp;
    },

    dispose: function (renderer) {
        renderer.disposeFrameBuffer(this._frameBuffer);
        // Dispose textures
        renderer.disposeTexture(this.vectorFieldTexture);
        renderer.disposeTexture(this._spawnTexture);
        renderer.disposeTexture(this._particleTexture0);
        renderer.disposeTexture(this._particleTexture1);
        renderer.disposeTexture(this._thisFrameTexture);
        renderer.disposeTexture(this._lastFrameTexture);

        renderer.disposeGeometry(this._particleLinesMesh.geometry);
        renderer.disposeGeometry(this._particlePointsMesh.geometry);
        renderer.disposeGeometry(this._lastFrameFullQuadMesh.geometry);

        if (this._spriteTexture) {
            renderer.disposeTexture(this._spriteTexture);
        }

        this._particlePass.dispose(renderer);
        this._downsamplePass.dispose(renderer);

        this._downsampleTextures.forEach(function (texture) {
            texture.dispose(renderer);
        });
    }
};

/* harmony default export */ const flowGL_VectorFieldParticleSurface = (VectorFieldParticleSurface);
;// CONCATENATED MODULE: ./src/chart/flowGL/FlowGLView.js








// TODO 百度地图不是 linear 的
/* harmony default export */ const FlowGLView = (external_echarts_.ChartView.extend({

    type: 'flowGL',

    __ecgl__: true,

    init: function (ecModel, api) {
        this.viewGL = new core_ViewGL('orthographic');
        this.groupGL = new util_graphicGL.Node();
        this.viewGL.add(this.groupGL);

        this._particleSurface = new flowGL_VectorFieldParticleSurface();

        var planeMesh = new util_graphicGL.Mesh({
            geometry: new util_graphicGL.PlaneGeometry(),
            material: new util_graphicGL.Material({
                shader: new util_graphicGL.Shader({
                    vertex: util_graphicGL.Shader.source('ecgl.color.vertex'),
                    fragment: util_graphicGL.Shader.source('ecgl.color.fragment')
                }),
                // Must enable blending and multiply alpha.
                // Or premultipliedAlpha will let the alpha useless.
                transparent: true
            })
        });
        planeMesh.material.enableTexture('diffuseMap');

        this.groupGL.add(planeMesh);

        this._planeMesh = planeMesh;

    },

    render: function (seriesModel, ecModel, api) {
        var particleSurface = this._particleSurface;
        // Set particleType before set others.
        particleSurface.setParticleType(seriesModel.get('particleType'));
        particleSurface.setSupersampling(seriesModel.get('supersampling'));

        this._updateData(seriesModel, api);
        this._updateCamera(api.getWidth(), api.getHeight(), api.getDevicePixelRatio());

        var particleDensity = util_retrieve.firstNotNull(seriesModel.get('particleDensity'), 128);
        particleSurface.setParticleDensity(particleDensity, particleDensity);

        var planeMesh = this._planeMesh;

        var time = +(new Date());
        var self = this;
        var firstFrame = true;
        planeMesh.__percent = 0;
        planeMesh.stopAnimation();
        planeMesh.animate('', { loop: true })
            .when(100000, {
                __percent: 1
            })
            .during(function () {
                var timeNow = + (new Date());
                var dTime = Math.min(timeNow - time, 20);
                time = time + dTime;
                if (self._renderer) {
                    particleSurface.update(self._renderer, api, dTime / 1000, firstFrame);
                    planeMesh.material.set('diffuseMap', particleSurface.getSurfaceTexture());
                    // planeMesh.material.set('diffuseMap', self._particleSurface.vectorFieldTexture);
                }
                firstFrame = false;
            })
            .start();

        var itemStyleModel = seriesModel.getModel('itemStyle');
        var color = util_graphicGL.parseColor(itemStyleModel.get('color'));
        color[3] *= util_retrieve.firstNotNull(itemStyleModel.get('opacity'), 1);
        planeMesh.material.set('color', color);

        particleSurface.setColorTextureImage(seriesModel.get('colorTexture'), api);
        particleSurface.setParticleSize(seriesModel.get('particleSize'));
        particleSurface.particleSpeedScaling = seriesModel.get('particleSpeed');
        particleSurface.motionBlurFactor = 1.0 - Math.pow(0.1, seriesModel.get('particleTrail'));
    },

    updateTransform: function (seriesModel, ecModel, api) {
        this._updateData(seriesModel, api);
    },

    afterRender: function (globeModel, ecModel, api, layerGL) {
        var renderer = layerGL.renderer;
        this._renderer = renderer;
    },

    _updateData: function (seriesModel, api) {
        var coordSys = seriesModel.coordinateSystem;
        var dims = coordSys.dimensions.map(function (coordDim) {
            return seriesModel.coordDimToDataDim(coordDim)[0];
        });

        var data = seriesModel.getData();
        var xExtent = data.getDataExtent(dims[0]);
        var yExtent = data.getDataExtent(dims[1]);

        var gridWidth = seriesModel.get('gridWidth');
        var gridHeight = seriesModel.get('gridHeight');

        if (gridWidth == null || gridWidth === 'auto') {
            // TODO not accurate.
            var aspect = (xExtent[1] - xExtent[0]) / (yExtent[1] - yExtent[0]);
            gridWidth = Math.round(Math.sqrt(aspect * data.count()));
        }
        if (gridHeight == null || gridHeight === 'auto') {
            gridHeight = Math.ceil(data.count() / gridWidth);
        }

        var vectorFieldTexture = this._particleSurface.vectorFieldTexture;

        // Half Float needs Uint16Array
        var pixels = vectorFieldTexture.pixels;
        if (!pixels || pixels.length !== gridHeight * gridWidth * 4) {
            pixels = vectorFieldTexture.pixels = new Float32Array(gridWidth * gridHeight * 4);
        }
        else {
            for (var i = 0; i < pixels.length; i++) {
                pixels[i] = 0;
            }
        }

        var maxMag = 0;
        var minMag = Infinity;

        var points = new Float32Array(data.count() * 2);
        var offset = 0;
        var bbox = [[Infinity, Infinity], [-Infinity, -Infinity]];

        data.each([dims[0], dims[1], 'vx', 'vy'], function (x, y, vx, vy) {
            var pt = coordSys.dataToPoint([x, y]);
            points[offset++] = pt[0];
            points[offset++] = pt[1];
            bbox[0][0] = Math.min(pt[0], bbox[0][0]);
            bbox[0][1] = Math.min(pt[1], bbox[0][1]);
            bbox[1][0] = Math.max(pt[0], bbox[1][0]);
            bbox[1][1] = Math.max(pt[1], bbox[1][1]);

            var mag = Math.sqrt(vx * vx + vy * vy);
            maxMag = Math.max(maxMag, mag);
            minMag = Math.min(minMag, mag);
        });

        data.each(['vx', 'vy'], function (vx, vy, i) {
            var xPix = Math.round((points[i * 2] - bbox[0][0]) / (bbox[1][0] - bbox[0][0]) * (gridWidth - 1));
            var yPix = gridHeight - 1 - Math.round((points[i * 2 + 1] - bbox[0][1]) / (bbox[1][1] - bbox[0][1]) * (gridHeight - 1));

            var idx = (yPix * gridWidth + xPix) * 4;

            pixels[idx] = (vx / maxMag * 0.5 + 0.5);
            pixels[idx + 1] = (vy / maxMag * 0.5 + 0.5);
            pixels[idx + 3] = 1;
        });

        vectorFieldTexture.width = gridWidth;
        vectorFieldTexture.height = gridHeight;

        if (seriesModel.get('coordinateSystem') === 'bmap') {
            this._fillEmptyPixels(vectorFieldTexture);
        }

        vectorFieldTexture.dirty();

        this._updatePlanePosition(bbox[0], bbox[1], seriesModel,api);
        this._updateGradientTexture(data.getVisual('visualMeta'), [minMag, maxMag]);

    },
    // PENDING Use grid mesh ? or delaunay triangulation?
    _fillEmptyPixels: function (texture) {
        var pixels = texture.pixels;
        var width = texture.width;
        var height = texture.height;

        function fetchPixel(x, y, rg) {
            x = Math.max(Math.min(x, width - 1), 0);
            y = Math.max(Math.min(y, height - 1), 0);
            var idx = (y * (width - 1) + x) * 4;
            if (pixels[idx + 3] === 0) {
                return false;
            }
            rg[0] = pixels[idx];
            rg[1] = pixels[idx + 1];
            return true;
        }

        function addPixel(a, b, out) {
            out[0] = a[0] + b[0];
            out[1] = a[1] + b[1];
        }

        var center = [], left = [], right = [], top = [], bottom = [];
        var weight = 0;
        for (var y = 0; y < height; y++) {
            for (var x = 0; x < width; x++) {
                var idx = (y * (width - 1) + x) * 4;
                if (pixels[idx + 3] === 0) {
                    weight = center[0] = center[1] = 0;
                    if (fetchPixel(x - 1, y, left)) {
                        weight++; addPixel(left, center, center);
                    }
                    if (fetchPixel(x + 1, y, right)) {
                        weight++; addPixel(right, center, center);
                    }
                    if (fetchPixel(x, y - 1, top)) {
                        weight++; addPixel(top, center, center);
                    }
                    if (fetchPixel(x, y + 1, bottom)) {
                        weight++; addPixel(bottom, center, center);
                    }
                    center[0] /= weight;
                    center[1] /= weight;
                    // PENDING If overwrite. bilinear interpolation.
                    pixels[idx] = center[0];
                    pixels[idx + 1] = center[1];
                }
                pixels[idx + 3] = 1;
            }
        }
    },

    _updateGradientTexture: function (visualMeta, magExtent) {
        if (!visualMeta || !visualMeta.length) {
            this._particleSurface.setGradientTexture(null);
            return;
        }
        // TODO Different dimensions
        this._gradientTexture = this._gradientTexture || new util_graphicGL.Texture2D({
            image: document.createElement('canvas')
        });
        var gradientTexture = this._gradientTexture;
        var canvas = gradientTexture.image;
        canvas.width = 200;
        canvas.height = 1;
        var ctx = canvas.getContext('2d');
        var gradient = ctx.createLinearGradient(0, 0.5, canvas.width, 0.5);
        visualMeta[0].stops.forEach(function (stop) {
            var offset;
            if (magExtent[1] === magExtent[0]) {
                offset = 0;
            }
            else {
                offset = stop.value / magExtent[1];
                offset = Math.min(Math.max(offset, 0), 1);
            }

            gradient.addColorStop(offset, stop.color);
        });
        ctx.fillStyle = gradient;
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        gradientTexture.dirty();

        this._particleSurface.setGradientTexture(this._gradientTexture);
    },

    _updatePlanePosition: function (leftTop, rightBottom, seriesModel, api) {
        var limitedResult = this._limitInViewportAndFullFill(leftTop, rightBottom, seriesModel, api);
        leftTop = limitedResult.leftTop;
        rightBottom = limitedResult.rightBottom;
        this._particleSurface.setRegion(limitedResult.region);

        this._planeMesh.position.set(
            (leftTop[0] + rightBottom[0]) / 2,
            api.getHeight() - (leftTop[1] + rightBottom[1]) / 2,
            0
        );

        var width = rightBottom[0] - leftTop[0];
        var height = rightBottom[1] - leftTop[1];
        this._planeMesh.scale.set(width / 2, height / 2, 1);

        this._particleSurface.resize(
            Math.max(Math.min(width, 2048), 1),
            Math.max(Math.min(height, 2048), 1)
        );

        if (this._renderer) {
            this._particleSurface.clearFrame(this._renderer);
        }
    },

    _limitInViewportAndFullFill: function (leftTop, rightBottom, seriesModel, api) {
        var newLeftTop = [
            Math.max(leftTop[0], 0),
            Math.max(leftTop[1], 0)
        ];
        var newRightBottom = [
            Math.min(rightBottom[0], api.getWidth()),
            Math.min(rightBottom[1], api.getHeight())
        ];
        // Tiliing in lng orientation.
        if (seriesModel.get('coordinateSystem') === 'bmap') {
            var lngRange = seriesModel.getData().getDataExtent(seriesModel.coordDimToDataDim('lng')[0]);
            // PENDING, consider grid density
            var isContinuous = Math.floor(lngRange[1] - lngRange[0]) >= 359;
            if (isContinuous) {
                if (newLeftTop[0] > 0) {
                    newLeftTop[0] = 0;
                }
                if (newRightBottom[0] < api.getWidth()) {
                    newRightBottom[0] = api.getWidth();
                }
            }
        }

        var width = rightBottom[0] - leftTop[0];
        var height = rightBottom[1] - leftTop[1];
        var newWidth = newRightBottom[0] - newLeftTop[0];
        var newHeight = newRightBottom[1] - newLeftTop[1];

        var region = [
            (newLeftTop[0] - leftTop[0]) / width,
            1.0 - newHeight / height - (newLeftTop[1] - leftTop[1]) / height,
            newWidth / width,
            newHeight / height
        ];

        return {
            leftTop: newLeftTop,
            rightBottom: newRightBottom,
            region: region
        };
    },

    _updateCamera: function (width, height, dpr) {
        this.viewGL.setViewport(0, 0, width, height, dpr);
        var camera = this.viewGL.camera;
        // FIXME  bottom can't be larger than top
        camera.left = camera.bottom = 0;
        camera.top = height;
        camera.right = width;
        camera.near = 0;
        camera.far = 100;
        camera.position.z = 10;
    },

    remove: function () {
        this._planeMesh.stopAnimation();
        this.groupGL.removeAll();
    },

    dispose: function () {
        if (this._renderer) {
            this._particleSurface.dispose(this._renderer);
        }
        this.groupGL.removeAll();
    }
}));

;// CONCATENATED MODULE: ./src/chart/flowGL/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function flowGL_install_install(registers) {
    registers.registerChartView(FlowGLView);
    registers.registerSeriesModel(FlowGLSeries);
}
;// CONCATENATED MODULE: ./src/chart/flowGL.js


(0,external_echarts_.use)(flowGL_install_install);
;// CONCATENATED MODULE: ./src/chart/linesGL/LinesGLSeries.js



var LinesGLSeries = external_echarts_.SeriesModel.extend({

    type: 'series.linesGL',

    dependencies: ['grid', 'geo'],

    visualStyleAccessPath: 'lineStyle',
    visualDrawType: 'stroke',

    streamEnabled: true,

    init: function (option) {
        var result = this._processFlatCoordsArray(option.data);
        this._flatCoords = result.flatCoords;
        this._flatCoordsOffset = result.flatCoordsOffset;
        if (result.flatCoords) {
            option.data = new Float32Array(result.count);
        }

        LinesGLSeries.superApply(this, 'init', arguments);
    },

    mergeOption: function (option) {
        var result = this._processFlatCoordsArray(option.data);
        this._flatCoords = result.flatCoords;
        this._flatCoordsOffset = result.flatCoordsOffset;
        if (result.flatCoords) {
            option.data = new Float32Array(result.count);
        }

        LinesGLSeries.superApply(this, 'mergeOption', arguments);
    },

    appendData: function (params) {
        var result = this._processFlatCoordsArray(params.data);
        if (result.flatCoords) {
            if (!this._flatCoords) {
                this._flatCoords = result.flatCoords;
                this._flatCoordsOffset = result.flatCoordsOffset;
            }
            else {
                this._flatCoords = concatArray(this._flatCoords, result.flatCoords);
                this._flatCoordsOffset = concatArray(this._flatCoordsOffset, result.flatCoordsOffset);
            }
            params.data = new Float32Array(result.count);
        }

        this.getRawData().appendData(params.data);
    },

    _getCoordsFromItemModel: function (idx) {
        var itemModel = this.getData().getItemModel(idx);
        var coords = (itemModel.option instanceof Array)
            ? itemModel.option : itemModel.getShallow('coords');

        if (true) {
            if (!(coords instanceof Array && coords.length > 0 && coords[0] instanceof Array)) {
                throw new Error('Invalid coords ' + JSON.stringify(coords) + '. Lines must have 2d coords array in data item.');
            }
        }
        return coords;
    },

    getLineCoordsCount: function (idx) {
        if (this._flatCoordsOffset) {
            return this._flatCoordsOffset[idx * 2 + 1];
        }
        else {
            return this._getCoordsFromItemModel(idx).length;
        }
    },

    getLineCoords: function (idx, out) {
        if (this._flatCoordsOffset) {
            var offset = this._flatCoordsOffset[idx * 2];
            var len = this._flatCoordsOffset[idx * 2 + 1];
            for (var i = 0; i < len; i++) {
                out[i] = out[i] || [];
                out[i][0] = this._flatCoords[offset + i * 2];
                out[i][1] = this._flatCoords[offset + i * 2 + 1];
            }
            return len;
        }
        else {
            var coords = this._getCoordsFromItemModel(idx);
            for (var i = 0; i < coords.length; i++) {
                out[i] = out[i] || [];
                out[i][0] = coords[i][0];
                out[i][1] = coords[i][1];
            }
            return coords.length;
        }
    },

    _processFlatCoordsArray: function (data) {
        var startOffset = 0;
        if (this._flatCoords) {
            startOffset = this._flatCoords.length;
        }
        // Stored as a typed array. In format
        // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |
        if (typeof data[0] === 'number') {
            var len = data.length;
            // Store offset and len of each segment
            var coordsOffsetAndLenStorage = new Uint32Array(len);
            var coordsStorage = new Float64Array(len);
            var coordsCursor = 0;
            var offsetCursor = 0;
            var dataCount = 0;
            for (var i = 0; i < len;) {
                dataCount++;
                var count = data[i++];
                // Offset
                coordsOffsetAndLenStorage[offsetCursor++] = coordsCursor + startOffset;
                // Len
                coordsOffsetAndLenStorage[offsetCursor++] = count;
                for (var k = 0; k < count; k++) {
                    var x = data[i++];
                    var y = data[i++];
                    coordsStorage[coordsCursor++] = x;
                    coordsStorage[coordsCursor++] = y;

                    if (i > len) {
                        if (true) {
                            throw new Error('Invalid data format.');
                        }
                    }
                }
            }

            return {
                flatCoordsOffset: new Uint32Array(coordsOffsetAndLenStorage.buffer, 0, offsetCursor),
                flatCoords: coordsStorage,
                count: dataCount
            };
        }

        return {
            flatCoordsOffset: null,
            flatCoords: null,
            count: data.length
        };
    },

    getInitialData: function (option, ecModel) {
        var lineData = new external_echarts_.List(['value'], this);
        lineData.hasItemOption = false;

        lineData.initData(option.data, [], function (dataItem, dimName, dataIndex, dimIndex) {
            // dataItem is simply coords
            if (dataItem instanceof Array) {
                return NaN;
            }
            else {
                lineData.hasItemOption = true;
                var value = dataItem.value;
                if (value != null) {
                    return value instanceof Array ? value[dimIndex] : value;
                }
            }
        });

        return lineData;
    },

    defaultOption: {
        coordinateSystem: 'geo',
        zlevel: 10,

        progressive: 1e4,
        progressiveThreshold: 5e4,

        // Cartesian coordinate system
        // xAxisIndex: 0,
        // yAxisIndex: 0,

        // Geo coordinate system
        // geoIndex: 0,

        // Support source-over, lighter
        blendMode: 'source-over',

        lineStyle: {
            opacity: 0.8
        },

        postEffect: {
            enable: false,
            colorCorrection: {
                exposure: 0,
                brightness: 0,
                contrast: 1,
                saturation: 1,
                enable: true
            }
        }
    }
});

/* harmony default export */ const linesGL_LinesGLSeries = (LinesGLSeries);
;// CONCATENATED MODULE: ./src/chart/linesGL/LinesGLView.js









/* harmony default export */ const LinesGLView = (external_echarts_.ChartView.extend({

    type: 'linesGL',

    __ecgl__: true,

    init: function (ecModel, api) {
        this.groupGL = new util_graphicGL.Node();
        this.viewGL = new core_ViewGL('orthographic');
        this.viewGL.add(this.groupGL);

        this._glViewHelper = new common_GLViewHelper(this.viewGL);

        this._nativeLinesShader = util_graphicGL.createShader('ecgl.lines3D');
        this._meshLinesShader = util_graphicGL.createShader('ecgl.meshLines3D');

        this._linesMeshes = [];
        this._currentStep = 0;
    },

    render: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();
        this._glViewHelper.reset(seriesModel, api);

        var linesMesh = this._linesMeshes[0];
        if (!linesMesh) {
            linesMesh = this._linesMeshes[0] = this._createLinesMesh(seriesModel);
        }
        this._linesMeshes.length = 1;

        this.groupGL.add(linesMesh);
        this._updateLinesMesh(seriesModel, linesMesh, 0, seriesModel.getData().count());

        this.viewGL.setPostEffect(seriesModel.getModel('postEffect'), api);
    },

    incrementalPrepareRender: function (seriesModel, ecModel, api) {
        this.groupGL.removeAll();
        this._glViewHelper.reset(seriesModel, api);

        this._currentStep = 0;

        this.viewGL.setPostEffect(seriesModel.getModel('postEffect'), api);
    },

    incrementalRender: function (params, seriesModel, ecModel, api) {
        var linesMesh = this._linesMeshes[this._currentStep];
        if (!linesMesh) {
            linesMesh = this._createLinesMesh(seriesModel);
            this._linesMeshes[this._currentStep] = linesMesh;
        }
        this._updateLinesMesh(seriesModel, linesMesh, params.start, params.end);
        this.groupGL.add(linesMesh);
        api.getZr().refresh();

        this._currentStep++;
    },

    updateTransform: function (seriesModel, ecModel, api) {
        if (seriesModel.coordinateSystem.getRoamTransform) {
            this._glViewHelper.updateTransform(seriesModel, api);
        }
    },

    _createLinesMesh: function (seriesModel) {
        var linesMesh = new util_graphicGL.Mesh({
            $ignorePicking: true,
            material: new util_graphicGL.Material({
                shader: util_graphicGL.createShader('ecgl.lines3D'),
                transparent: true,
                depthMask: false,
                depthTest: false
            }),
            geometry: new Lines2D({
                segmentScale: 10,
                useNativeLine: true,
                dynamic: false
            }),
            mode: util_graphicGL.Mesh.LINES,
            culling: false
        });

        return linesMesh;
    },

    _updateLinesMesh: function (seriesModel, linesMesh, start, end) {
        var data = seriesModel.getData();
        linesMesh.material.blend = seriesModel.get('blendMode') === 'lighter'
            ? util_graphicGL.additiveBlend : null;
        var curveness = seriesModel.get('lineStyle.curveness') || 0;
        var isPolyline = seriesModel.get('polyline');
        var geometry = linesMesh.geometry;
        var coordSys = seriesModel.coordinateSystem;

        var lineWidth = util_retrieve.firstNotNull(seriesModel.get('lineStyle.width'), 1);

        if (lineWidth > 1) {
            if (linesMesh.material.shader !== this._meshLinesShader) {
                linesMesh.material.attachShader(this._meshLinesShader);
            }
            linesMesh.mode = util_graphicGL.Mesh.TRIANGLES;
        }
        else {
            if (linesMesh.material.shader !== this._nativeLinesShader) {
                linesMesh.material.attachShader(this._nativeLinesShader);
            }
            linesMesh.mode = util_graphicGL.Mesh.LINES;
        }

        start = start || 0;
        end = end || data.count();

        geometry.resetOffset();
        var vertexCount = 0;
        var triangleCount = 0;
        var p0 = [];
        var p1 = [];
        var p2 = [];
        var p3 = [];

        var lineCoords = [];

        var t = 0.3;
        var t2 = 0.7;

        function updateBezierControlPoints() {
            p1[0] = (p0[0] * t2 + p3[0] * t) - (p0[1] - p3[1]) * curveness;
            p1[1] = (p0[1] * t2 + p3[1] * t) - (p3[0] - p0[0]) * curveness;
            p2[0] = (p0[0] * t + p3[0] * t2) - (p0[1] - p3[1]) * curveness;
            p2[1] = (p0[1] * t + p3[1] * t2) - (p3[0] - p0[0]) * curveness;
        }
        if (isPolyline || curveness !== 0) {
            for (var idx = start; idx < end; idx++) {
                if (isPolyline) {
                    var count = seriesModel.getLineCoordsCount(idx);
                    vertexCount += geometry.getPolylineVertexCount(count);
                    triangleCount += geometry.getPolylineTriangleCount(count);
                }
                else {
                    seriesModel.getLineCoords(idx, lineCoords);
                    this._glViewHelper.dataToPoint(coordSys, lineCoords[0], p0);
                    this._glViewHelper.dataToPoint(coordSys, lineCoords[1], p3);
                    updateBezierControlPoints();

                    vertexCount += geometry.getCubicCurveVertexCount(p0, p1, p2, p3);
                    triangleCount += geometry.getCubicCurveTriangleCount(p0, p1, p2, p3);
                }
            }
        }
        else {
            var lineCount = end - start;
            vertexCount += lineCount * geometry.getLineVertexCount();
            triangleCount += lineCount * geometry.getLineVertexCount();
        }
        geometry.setVertexCount(vertexCount);
        geometry.setTriangleCount(triangleCount);

        var dataIndex = start;
        var colorArr = [];
        for (var idx = start; idx < end; idx++) {
            util_graphicGL.parseColor(getItemVisualColor(data, dataIndex), colorArr);
            var opacity = util_retrieve.firstNotNull(getItemVisualOpacity(data, dataIndex), 1);
            colorArr[3] *= opacity;

            var count = seriesModel.getLineCoords(idx, lineCoords);
            for (var k = 0; k < count; k++) {
                this._glViewHelper.dataToPoint(coordSys, lineCoords[k], lineCoords[k]);
            }

            if (isPolyline) {
                geometry.addPolyline(lineCoords, colorArr, lineWidth, 0, count);
            }
            else if (curveness !== 0) {
                p0 = lineCoords[0];
                p3 = lineCoords[1];
                updateBezierControlPoints();
                geometry.addCubicCurve(p0, p1, p2, p3, colorArr, lineWidth);
            }
            else {
                geometry.addPolyline(lineCoords, colorArr, lineWidth, 0, 2);
            }
            dataIndex++;
        }
    },

    dispose: function () {
        this.groupGL.removeAll();
    },

    remove: function () {
        this.groupGL.removeAll();
    }
}));
;// CONCATENATED MODULE: ./src/chart/linesGL/install.js
// TODO ECharts GL must be imported whatever component,charts is imported.





function linesGL_install_install(registers) {
    registers.registerChartView(LinesGLView);
    registers.registerSeriesModel(linesGL_LinesGLSeries);
}
;// CONCATENATED MODULE: ./src/chart/linesGL.js


(0,external_echarts_.use)(linesGL_install_install);
;// CONCATENATED MODULE: ./src/export/all.js





















/***/ }),

/***/ "echarts/lib/echarts":
/*!**************************!*\
  !*** external "echarts" ***!
  \**************************/
/***/ ((module) => {

module.exports = __WEBPACK_EXTERNAL_MODULE_echarts_lib_echarts__;

/***/ })

/******/ 	});
/************************************************************************/
/******/ 	// The module cache
/******/ 	var __webpack_module_cache__ = {};
/******/ 	
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/ 		// Check if module is in cache
/******/ 		if(__webpack_module_cache__[moduleId]) {
/******/ 			return __webpack_module_cache__[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = __webpack_module_cache__[moduleId] = {
/******/ 			// no module.id needed
/******/ 			// no module.loaded needed
/******/ 			exports: {}
/******/ 		};
/******/ 	
/******/ 		// Execute the module function
/******/ 		__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/ 	
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/global */
/******/ 	(() => {
/******/ 		__webpack_require__.g = (function() {
/******/ 			if (typeof globalThis === 'object') return globalThis;
/******/ 			try {
/******/ 				return this || new Function('return this')();
/******/ 			} catch (e) {
/******/ 				if (typeof window === 'object') return window;
/******/ 			}
/******/ 		})();
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/************************************************************************/
/******/ 	// module exports must be returned from runtime so entry inlining is disabled
/******/ 	// startup
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__("./src/export/all.js");
/******/ })()
;
});
//# sourceMappingURL=echarts-gl.js.map