UNPKG

chartx

Version:

Data Visualization Chart Library

1,909 lines (1,570 loc) 1.88 MB
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function commonjsRequire () { throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs'); } function unwrapExports (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var interopRequireDefault = createCommonjsModule(function (module) { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } module.exports = _interopRequireDefault; }); unwrapExports(interopRequireDefault); function unwrapExports$1 (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } function createCommonjsModule$1(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } var classCallCheck = createCommonjsModule$1(function (module) { function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } module.exports = _classCallCheck; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _classCallCheck = unwrapExports$1(classCallCheck); var createClass = createCommonjsModule$1(function (module) { function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } module.exports = _createClass; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _createClass = unwrapExports$1(createClass); var assertThisInitialized = createCommonjsModule$1(function (module) { function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } module.exports = _assertThisInitialized; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _assertThisInitialized = unwrapExports$1(assertThisInitialized); var setPrototypeOf = createCommonjsModule$1(function (module) { function _setPrototypeOf(o, p) { module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; module.exports["default"] = module.exports, module.exports.__esModule = true; return _setPrototypeOf(o, p); } module.exports = _setPrototypeOf; module.exports["default"] = module.exports, module.exports.__esModule = true; }); unwrapExports$1(setPrototypeOf); var inherits = createCommonjsModule$1(function (module) { function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) setPrototypeOf(subClass, superClass); } module.exports = _inherits; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _inherits = unwrapExports$1(inherits); var _typeof_1 = createCommonjsModule$1(function (module) { function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { module.exports = _typeof = function _typeof(obj) { return typeof obj; }; module.exports["default"] = module.exports, module.exports.__esModule = true; } else { module.exports = _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; module.exports["default"] = module.exports, module.exports.__esModule = true; } return _typeof(obj); } module.exports = _typeof; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _typeof = unwrapExports$1(_typeof_1); var possibleConstructorReturn = createCommonjsModule$1(function (module) { var _typeof = _typeof_1["default"]; function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return assertThisInitialized(self); } module.exports = _possibleConstructorReturn; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _possibleConstructorReturn = unwrapExports$1(possibleConstructorReturn); var getPrototypeOf = createCommonjsModule$1(function (module) { function _getPrototypeOf(o) { module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; module.exports["default"] = module.exports, module.exports.__esModule = true; return _getPrototypeOf(o); } module.exports = _getPrototypeOf; module.exports["default"] = module.exports, module.exports.__esModule = true; }); var _getPrototypeOf = unwrapExports$1(getPrototypeOf); var _ = {}; var breaker = {}; var ArrayProto = Array.prototype, ObjProto = Object.prototype; // Create quick reference variables for speed access to core prototypes. var push = ArrayProto.push, slice = ArrayProto.slice, concat = ArrayProto.concat, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. var nativeForEach = ArrayProto.forEach, nativeMap = ArrayProto.map, nativeFilter = ArrayProto.filter, nativeEvery = ArrayProto.every, nativeSome = ArrayProto.some, nativeIndexOf = ArrayProto.indexOf, nativeIsArray = Array.isArray, nativeKeys = Object.keys; var shallowProperty = function shallowProperty(key) { return function (obj) { return obj == null ? void 0 : obj[key]; }; }; var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var getLength = shallowProperty('length'); var isArrayLike = function isArrayLike(collection) { var length = getLength(collection); return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; }; _.values = function (obj) { var keys = _.keys(obj); var length = keys.length; var values = new Array(length); for (var i = 0; i < length; i++) { values[i] = obj[keys[i]]; } return values; }; _.keys = nativeKeys || function (obj) { if (obj !== Object(obj)) throw new TypeError('Invalid object'); var keys = []; for (var key in obj) { if (_.has(obj, key)) keys.push(key); } return keys; }; _.has = function (obj, key) { return hasOwnProperty.call(obj, key); }; var each = _.each = _.forEach = function (obj, iterator, context) { if (obj == null) return; if (nativeForEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); } else if (obj.length === +obj.length) { for (var i = 0, length = obj.length; i < length; i++) { if (iterator.call(context, obj[i], i, obj) === breaker) return; } } else { var keys = _.keys(obj); for (var i = 0, length = keys.length; i < length; i++) { if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return; } } }; _.compact = function (array) { return _.filter(array, _.identity); }; _.filter = _.select = function (obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); each(obj, function (value, index, list) { if (iterator.call(context, value, index, list)) results.push(value); }); return results; }; each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function (name) { _['is' + name] = function (obj) { return toString.call(obj) == '[object ' + name + ']'; }; }); //if (!_.isArguments(arguments)) { _.isArguments = function (obj) { return !!(obj && _.has(obj, 'callee')); }; //} if (typeof /./ !== 'function') { _.isFunction = function (obj) { return typeof obj === 'function'; }; } _.isFinite = function (obj) { return isFinite(obj) && !isNaN(parseFloat(obj)); }; _.isNaN = function (obj) { return _.isNumber(obj) && obj != +obj; }; _.isBoolean = function (obj) { return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; }; _.isNull = function (obj) { return obj === null; }; _.isEmpty = function (obj) { if (obj == null) return true; if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; for (var key in obj) { if (_.has(obj, key)) return false; } return true; }; _.isElement = function (obj) { return !!(obj && obj.nodeType === 1); }; _.isArray = nativeIsArray || function (obj) { return toString.call(obj) == '[object Array]'; }; _.isObject = function (obj) { return obj === Object(obj); }; _.identity = function (value) { return value; }; _.indexOf = function (array, item, isSorted) { if (array == null) return -1; var i = 0, length = array.length; if (isSorted) { if (typeof isSorted == 'number') { i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted; } else { i = _.sortedIndex(array, item); return array[i] === item ? i : -1; } } if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); for (; i < length; i++) { if (array[i] === item) return i; } return -1; }; _.isWindow = function (obj) { return obj != null && obj == obj.window; }; // Internal implementation of a recursive `flatten` function. var flatten = function flatten(input, shallow, output) { if (shallow && _.every(input, _.isArray)) { return concat.apply(output, input); } each(input, function (value) { if (_.isArray(value) || _.isArguments(value)) { shallow ? push.apply(output, value) : flatten(value, shallow, output); } else { output.push(value); } }); return output; }; // Flatten out an array, either recursively (by default), or just one level. _.flatten = function (array, shallow) { return flatten(array, shallow, []); }; _.every = _.all = function (obj, iterator, context) { iterator || (iterator = _.identity); var result = true; if (obj == null) return result; if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); each(obj, function (value, index, list) { if (!(result = result && iterator.call(context, value, index, list))) return breaker; }); return !!result; }; // Return the minimum element (or element-based computation). _.min = function (obj, iterator, context) { if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.min.apply(Math, obj); } if (!iterator && _.isEmpty(obj)) return Infinity; var result = { computed: Infinity, value: Infinity }; each(obj, function (value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed < result.computed && (result = { value: value, computed: computed }); }); return result.value; }; // Return the maximum element or (element-based computation). // Can't optimize arrays of integers longer than 65,535 elements. // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797) _.max = function (obj, iterator, context) { if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { return Math.max.apply(Math, obj); } if (!iterator && _.isEmpty(obj)) return -Infinity; var result = { computed: -Infinity, value: -Infinity }; each(obj, function (value, index, list) { var computed = iterator ? iterator.call(context, value, index, list) : value; computed > result.computed && (result = { value: value, computed: computed }); }); return result.value; }; // Return the first value which passes a truth test. Aliased as `detect`. _.find = _.detect = function (obj, iterator, context) { var result; any(obj, function (value, index, list) { if (iterator.call(context, value, index, list)) { result = value; return true; } }); return result; }; // Determine if at least one element in the object matches a truth test. // Delegates to **ECMAScript 5**'s native `some` if available. // Aliased as `any`. var any = _.some = _.any = function (obj, iterator, context) { iterator || (iterator = _.identity); var result = false; if (obj == null) return result; if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); each(obj, function (value, index, list) { if (result || (result = iterator.call(context, value, index, list))) return breaker; }); return !!result; }; // Return a version of the array that does not contain the specified value(s). _.without = function (array) { return _.difference(array, slice.call(arguments, 1)); }; // Take the difference between one array and a number of other arrays. // Only the elements present in just the first array will remain. _.difference = function (array) { var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); return _.filter(array, function (value) { return !_.contains(rest, value); }); }; // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function (array, isSorted, iterator, context) { if (_.isFunction(isSorted)) { context = iterator; iterator = isSorted; isSorted = false; } var initial = iterator ? _.map(array, iterator, context) : array; var results = []; var seen = []; each(initial, function (value, index) { if (isSorted ? !index || seen[seen.length - 1] !== value : !_.contains(seen, value)) { seen.push(value); results.push(array[index]); } }); return results; }; // Return the results of applying the iterator to each element. // Delegates to **ECMAScript 5**'s native `map` if available. _.map = _.collect = function (obj, iterator, context) { var results = []; if (obj == null) return results; if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); each(obj, function (value, index, list) { results.push(iterator.call(context, value, index, list)); }); return results; }; // Determine if the array or object contains a given value (using `===`). // Aliased as `include`. _.contains = _.include = function (obj, target) { if (obj == null) return false; if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; return any(obj, function (value) { return value === target; }); }; // Convenience version of a common use case of `map`: fetching a property. _.pluck = function (obj, key) { return _.map(obj, function (value) { return value[key]; }); }; // Return a random integer between min and max (inclusive). _.random = function (min, max) { if (max == null) { max = min; min = 0; } return min + Math.floor(Math.random() * (max - min + 1)); }; // Shuffle a collection. _.shuffle = function (obj) { return _.sample(obj, Infinity); }; _.sample = function (obj, n, guard) { if (n == null || guard) { if (!isArrayLike(obj)) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj); var length = getLength(sample); n = Math.max(Math.min(n, length), 0); var last = length - 1; for (var index = 0; index < n; index++) { var rand = _.random(index, last); var temp = sample[index]; sample[index] = sample[rand]; sample[rand] = temp; } return sample.slice(0, n); }; /** * *如果是深度extend,第一个参数就设置为true */ _.extend = function () { var options, name, src, copy, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; if (typeof target === "boolean") { deep = target; target = arguments[1] || {}; i = 2; } if (_typeof(target) !== "object" && !_.isFunction(target)) { target = {}; } if (length === i) { target = this; --i; } for (; i < length; i++) { if ((options = arguments[i]) != null) { for (name in options) { src = target[name]; copy = options[name]; if (target === copy || copy === undefined) { continue; } if (deep && copy && _.isObject(copy) && copy.constructor === Object) { target[name] = _.extend(deep, src, copy); } else { target[name] = copy; } } } } return target; }; _.clone = function (obj) { if (!_.isObject(obj)) return obj; return _.isArray(obj) ? obj.slice() : _.extend(true, {}, obj); }; //********补存一些数学常用方法,暂放在这里文件下,后期多了单独成立一个类库 */ // compute euclidian modulo of m % n // https://en.wikipedia.org/wiki/Modulo_operation _.euclideanModulo = function (n, m) { return (n % m + m) % m; }; _.DEG2RAD = Math.PI / 180; _.RAD2DEG = 180 / Math.PI; _.degToRad = function (degrees) { return degrees * _.DEG2RAD; }; _.radToDeg = function (radians) { return radians * _.RAD2DEG; }; var Settings = { //设备分辨率 RESOLUTION: 1, /** * Target frames per millisecond. */ TARGET_FPMS: 0.06, /** * If set to true WebGL will attempt make textures mimpaped by default. * Mipmapping will only succeed if the base texture uploaded has power of two dimensions. */ MIPMAP_TEXTURES: true, /** * Default filter resolution. */ FILTER_RESOLUTION: 1, // TODO: maybe change to SPRITE.BATCH_SIZE: 2000 // TODO: maybe add PARTICLE.BATCH_SIZE: 15000 /** * The default sprite batch size. * * The default aims to balance desktop and mobile devices. */ SPRITE_BATCH_SIZE: 4096, /** * The prefix that denotes a URL is for a retina asset. */ RETINA_PREFIX: /@(.+)x/, RENDER_OPTIONS: { view: null, antialias: true, forceFXAA: false, autoResize: false, transparent: true, backgroundColor: 0x000000, clearBeforeRender: true, preserveDrawingBuffer: false, roundPixels: false }, TRANSFORM_MODE: 0, GC_MODE: 0, GC_MAX_IDLE: 60 * 60, GC_MAX_CHECK_COUNT: 60 * 10, WRAP_MODE: 0, SCALE_MODE: 0, PRECISION: 'mediump' }; var addOrRmoveEventHand = function addOrRmoveEventHand(domHand, ieHand) { if (!document) return; if (document[domHand]) { var eventDomFn = function eventDomFn(el, type, fn) { if (el.length) { for (var i = 0; i < el.length; i++) { eventDomFn(el[i], type, fn); } } else { el[domHand](type, fn, false); } }; return eventDomFn; } else { var eventFn = function eventFn(el, type, fn) { if (el.length) { for (var i = 0; i < el.length; i++) { eventFn(el[i], type, fn); } } else { el[ieHand]("on" + type, function () { return fn.call(el, window.event); }); } }; return eventFn; } }; var $ = { // dom操作相关代码 query: function query(el) { if (!el) return; if (_.isString(el)) { return document.getElementById(el); } if (el.nodeType == 1) { //则为一个element本身 return el; } if (el.length) { return el[0]; } return null; }, offset: function offset(el) { if (!el) { return { top: 0, left: 0 }; } var box = el.getBoundingClientRect(), doc = el.ownerDocument, body = doc.body, docElem = doc.documentElement, // for ie clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, // In Internet Explorer 7 getBoundingClientRect property is treated as physical, // while others are logical. Make all logical, like in IE8. zoom = 1; if (body.getBoundingClientRect) { var bound = body.getBoundingClientRect(); zoom = (bound.right - bound.left) / body.clientWidth; } if (zoom > 1) { clientTop = 0; clientLeft = 0; } var top = box.top / zoom + (window.pageYOffset || docElem && docElem.scrollTop / zoom || body.scrollTop / zoom) - clientTop, left = box.left / zoom + (window.pageXOffset || docElem && docElem.scrollLeft / zoom || body.scrollLeft / zoom) - clientLeft; return { top: top, left: left }; }, addEvent: addOrRmoveEventHand("addEventListener", "attachEvent"), removeEvent: addOrRmoveEventHand("removeEventListener", "detachEvent"), pageX: function pageX(e) { if (e.pageX) return e.pageX;else if (e.clientX) return e.clientX + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);else return null; }, pageY: function pageY(e) { if (e.pageY) return e.pageY;else if (e.clientY) return e.clientY + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);else return null; }, /** * 创建dom * @param {string} id dom id 待用 * @param {string} type : dom type, such as canvas, div etc. */ createCanvas: function createCanvas(_width, _height, id) { if (!document) return; var canvas = document.createElement("canvas"); canvas.style.position = 'absolute'; canvas.style.width = _width + 'px'; canvas.style.height = _height + 'px'; canvas.style.left = 0; canvas.style.top = 0; canvas.setAttribute('width', _width * Settings.RESOLUTION); canvas.setAttribute('height', _height * Settings.RESOLUTION); canvas.setAttribute('id', id); return canvas; }, createView: function createView(_width, _height, id) { var view = document.createElement("div"); view.className = "canvax-view"; view.style.cssText += "position:relative;width:100%;height:100%;"; var stageView = document.createElement("div"); stageView.style.cssText += "position:absolute;width:" + _width + "px;height:" + _height + "px;"; //用来存放一些dom元素 var domView = document.createElement("div"); domView.style.cssText += "position:absolute;width:" + _width + "px;height:" + _height + "px;"; view.appendChild(stageView); view.appendChild(domView); return { view: view, stageView: stageView, domView: domView }; } //dom相关代码结束 }; /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com */ var Utils = { mainFrameRate: 60, //默认主帧率 now: 0, /*给文本检测高宽专用*/ _pixelCtx: null, __emptyFunc: function __emptyFunc() {}, //retina 屏幕优化 _UID: 0, //该值为向上的自增长整数值 getUID: function getUID() { return this._UID++; }, createId: function createId(name) { //if end with a digit, then append an undersBase before appending var charCode = name.charCodeAt(name.length - 1); if (charCode >= 48 && charCode <= 57) name += "_"; return name + Utils.getUID(); }, canvasSupport: function canvasSupport() { return !!document.createElement('canvas').getContext; }, initElement: function initElement(canvas) { if (!window) return; if (window.FlashCanvas && FlashCanvas.initElement) { FlashCanvas.initElement(canvas); } return canvas; }, /** * 按照css的顺序,返回一个[上,右,下,左] */ getCssOrderArr: function getCssOrderArr(r) { var r1; var r2; var r3; var r4; 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; } return [r1, r2, r3, r4]; }, isWebGLSupported: function isWebGLSupported() { var contextOptions = { stencil: true }; try { if (!window.WebGLRenderingContext) //不存在直接return { return false; } var canvas = document.createElement('canvas'), gl = canvas.getContext('webgl', contextOptions) || canvas.getContext('experimental-webgl', contextOptions); return !!(gl && gl.getContextAttributes().stencil); //还要确实检测是否支持webGL模式 } catch (e) { return false; } }, checkOpt: function checkOpt(opt) { if (!opt) { opt = { context: {} }; } else { if (!opt.context) { opt.context = {}; } } return opt; } }; var _canvas = Utils.initElement($.createCanvas(1, 1, "_pixelCanvas")); Utils._pixelCtx = _canvas && _canvas.getContext('2d'); /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com) * * canvas 上委托的事件管理 */ var Event = function Event(evt) { var eventType = "CanvaxEvent"; if (_.isString(evt)) { eventType = evt; } if (_.isObject(evt) && evt.type) { eventType = evt.type; _.extend(this, evt); } this.target = null; this.currentTarget = null; this.type = eventType; this.point = null; var me = this; this._stopPropagation = false; //默认不阻止事件冒泡 this.stopPropagation = function () { me._stopPropagation = true; if (_.isObject(evt)) { evt._stopPropagation = true; } }; this._preventDefault = false; //是否组织事件冒泡 this.preventDefault = function () { me._preventDefault = true; if (_.isObject(evt)) { evt._preventDefault = true; } }; }; /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com) * * canvas 上委托的事件管理 */ var _mouseEvents = 'mousedown mouseup mouseover mousemove mouseout click dblclick wheel keydown keypress keyup'; var types = { _types: _mouseEvents.split(/,| /), register: function register(evts) { if (!evts) { return; } if (_.isString(evts)) { evts = evts.split(/,| /); } this._types = _mouseEvents.split(/,| /).concat(evts); }, get: function get() { return this._types; } }; /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com) * * 事件管理类 */ /** * 构造函数. * @name EventDispatcher * @class EventDispatcher类是可调度事件的类的基类,它允许显示列表上的任何对象都是一个事件目标。 */ var Manager = function Manager() { //事件映射表,格式为:{type1:[listener1, listener2], type2:[listener3, listener4]} this._eventMap = {}; }; Manager.prototype = { /** * 判断events里面是否有用户交互事件 */ _setEventEnable: function _setEventEnable() { if (this.children) return; //容器的_eventEnabled不受注册的用户交互事件影响 var hasInteractionEvent = false; for (var t in this._eventMap) { if (_.indexOf(types.get(), t) > -1) { hasInteractionEvent = true; } } this._eventEnabled = hasInteractionEvent; }, /* * 注册事件侦听器对象,以使侦听器能够接收事件通知。 */ _addEventListener: function _addEventListener(_type, listener) { if (typeof listener != "function") { //listener必须是个function呐亲 return false; } var addResult = true; var self = this; var types = _type; if (_.isString(_type)) { types = _type.split(/,| /); } _.each(types, function (type) { var map = self._eventMap[type]; if (!map) { map = self._eventMap[type] = []; map.push(listener); //self._eventEnabled = true; self._setEventEnable(); return true; } if (_.indexOf(map, listener) == -1) { map.push(listener); //self._eventEnabled = true; self._setEventEnable(); return true; } addResult = false; }); return addResult; }, /** * 删除事件侦听器。 */ _removeEventListener: function _removeEventListener(type, listener) { if (arguments.length == 1) return this.removeEventListenerByType(type); var map = this._eventMap[type]; if (!map) { return false; } for (var i = 0; i < map.length; i++) { var li = map[i]; if (li === listener) { map.splice(i, 1); if (map.length == 0) { delete this._eventMap[type]; this._setEventEnable(); //如果这个如果这个时候child没有任何事件侦听 /* if(_.isEmpty(this._eventMap)){ //那么该元素不再接受事件的检测 this._eventEnabled = false; } */ } return true; } } return false; }, /** * 删除指定类型的所有事件侦听器。 */ _removeEventListenerByType: function _removeEventListenerByType(type) { var map = this._eventMap[type]; if (!map) { delete this._eventMap[type]; this._setEventEnable(); //如果这个如果这个时候child没有任何事件侦听 /* if(_.isEmpty(this._eventMap)){ //那么该元素不再接受事件的检测 this._eventEnabled = false; } */ return true; } return false; }, /** * 删除所有事件侦听器。 */ _removeAllEventListeners: function _removeAllEventListeners() { this._eventMap = {}; this._eventEnabled = false; }, /** * 派发事件,调用事件侦听器。 */ _dispatchEvent: function _dispatchEvent(e) { var map = this._eventMap[e.type]; if (map) { if (!e.target) e.target = this; if (!e.currentTarget) e.currentTarget = this; map = map.slice(); for (var i = 0; i < map.length; i++) { var listener = map[i]; if (typeof listener == "function") { listener.call(this, e); } } } if (!e._stopPropagation) { //向上冒泡 if (this.parent) { e.currentTarget = this.parent; this.parent._dispatchEvent(e); } } return true; }, /** * 检查是否为指定事件类型注册了任何侦听器。 */ _hasEventListener: function _hasEventListener(type) { var map = this._eventMap[type]; return map != null && map.length > 0; } }; function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } var Dispatcher = /*#__PURE__*/function (_Manager) { _inherits(Dispatcher, _Manager); var _super = _createSuper(Dispatcher); function Dispatcher() { _classCallCheck(this, Dispatcher); return _super.call(this); } _createClass(Dispatcher, [{ key: "on", value: function on(type, listener) { this._addEventListener(type, listener); return this; } }, { key: "addEventListener", value: function addEventListener(type, listener) { this._addEventListener(type, listener); return this; } }, { key: "un", value: function un(type, listener) { this._removeEventListener(type, listener); return this; } }, { key: "removeEventListener", value: function removeEventListener(type, listener) { this._removeEventListener(type, listener); return this; } }, { key: "removeEventListenerByType", value: function removeEventListenerByType(type) { this._removeEventListenerByType(type); return this; } }, { key: "removeAllEventListeners", value: function removeAllEventListeners() { this._removeAllEventListeners(); return this; } //params 要传给evt的eventhandler处理函数的参数,会被merge到Canvax event中 }, { key: "fire", value: function fire(eventType, params) { //{currentTarget,point,target,type,_stopPropagation} var e = new Event(eventType); if (params) { for (var p in params) { if (p != "type") { e[p] = params[p]; } } } var me = this; _.each(eventType.split(" "), function (eType) { //然后,currentTarget要修正为自己 e.currentTarget = me; me.dispatchEvent(e); }); return this; } }, { key: "dispatchEvent", value: function dispatchEvent(evt) { //this instanceof DisplayObjectContainer ==> this.children //TODO: 这里import DisplayObjectContainer 的话,在displayObject里面的import EventDispatcher from "../event/EventDispatcher"; //会得到一个undefined,感觉是成了一个循环依赖的问题,所以这里换用简单的判断来判断自己是一个容易,拥有children if (this.children && evt.point) { var target = this.getObjectsUnderPoint(evt.point, 1)[0]; if (target) { target.dispatchEvent(evt); } return; } if (this.context && evt.type == "mouseover") { //记录dispatchEvent之前的心跳 var preHeartBeat = this._heartBeatNum; var pregAlpha = this.context.$model.globalAlpha; this._dispatchEvent(evt); if (preHeartBeat != this._heartBeatNum) { this._hoverClass = true; if (this.hoverClone) { var canvax = this.getStage().parent; //然后clone一份obj,添加到_bufferStage 中 var activShape = this.clone(true); activShape._transform = this.getConcatenatedMatrix(); canvax._bufferStage.addChildAt(activShape, 0); //然后把自己隐藏了 //用一个临时变量_globalAlpha 来存储自己之前的alpha this._globalAlpha = pregAlpha; this.context.globalAlpha = 0; } } return; } this._dispatchEvent(evt); if (this.context && evt.type == "mouseout") { if (this._hoverClass && this.hoverClone) { //说明刚刚over的时候有添加样式 var canvax = this.getStage().parent; this._hoverClass = false; canvax._bufferStage.removeChildById(this.id); if (this._globalAlpha) { this.context.globalAlpha = this._globalAlpha; delete this._globalAlpha; } } } return this; } }, { key: "hasEvent", value: function hasEvent(type) { return this._hasEventListener(type); } }, { key: "hasEventListener", value: function hasEventListener(type) { return this._hasEventListener(type); } }, { key: "hover", value: function hover(overFun, outFun) { this.on("mouseover", overFun); this.on("mouseout", outFun); return this; } }, { key: "once", value: function once(type, listener) { var me = this; var onceHandle = function onceHandle() { listener.apply(me, arguments); this.un(type, onceHandle); }; this.on(type, onceHandle); return this; } }]); return Dispatcher; }(Manager); /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com) * */ var Handler = function Handler(canvax) { var opt = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; this.canvax = canvax; this.curPoints = [{ x: 0, y: 0 }]; //X,Y 的 point 集合, 在touch下面则为 touch的集合,只是这个touch被添加了对应的x,y //当前激活的点对应的obj,在touch下可以是个数组,和上面的 curPoints 对应 this.curPointsTarget = []; this._touching = false; //正在拖动,前提是_touching=true this._draging = false; //当前的鼠标状态 this._cursor = "default"; this.target = this.canvax.view; //mouse体统中不需要配置drag,touch中会用到第三方的touch库,每个库的事件名称可能不一样, //就要这里配置,默认实现的是hammerjs的,所以默认可以在项目里引入hammerjs http://hammerjs.github.io/ this.drag = { start: "panstart", move: "panmove", end: "panend" }; this._opt = opt; _.extend(true, this, opt); }; //这样的好处是document.compareDocumentPosition只会在定义的时候执行一次。 var contains = document && document.compareDocumentPosition ? function (parent, child) { if (!child) { return false; } return !!(parent.compareDocumentPosition(child) & 16); } : function (parent, child) { if (!child) { return false; } return child !== child && (parent.contains ? parent.contains(child) : true); }; Handler.prototype = { init: function init() { //依次添加上浏览器的自带事件侦听 var me = this; if (this._opt.events) { types.register(this._opt.events); } if (me.target) { if (me.target.nodeType == undefined) ; $.addEvent(me.target, "contextmenu", function (e) { if (e && e.preventDefault) { e.preventDefault(); } else { window.event.returnValue = false; } }); _.each(types.get(), function (type) { //不再关心浏览器环境是否 'ontouchstart' in window //而是直接只管传给事件模块的是一个原生dom还是 jq对象 or hammer对象等 if (me.target.nodeType == 1) { $.addEvent(me.target, type, function (e) { me.__mouseHandler(e); }); } else { me.target.on(type, function (e) { me.__libHandler(e); }); } }); } }, bindEventHandle: function bindEventHandle(e, type) { if (type == 'mouse') { this.__mouseHandler.apply(this, [e]); } else { this.__libHandler.apply(this, [e]); } }, /* * 原生事件系统------------------------------------------------begin * 鼠标事件处理函数 **/ __mouseHandler: function __mouseHandler(e) { var me = this; var root = me.canvax; root.updateViewOffset(); me.curPoints = [{ x: $.pageX(e) - root.viewOffset.left, y: $.pageY(e) - root.viewOffset.top }]; //理论上来说,这里拿到point了后,就要计算这个point对应的target来push到curPointsTarget里, //但是因为在drag的时候其实是可以不用计算对应target的。 //所以放在了下面的me.__getcurPointsTarget( e , curMousePoint );常规mousemove中执行 var curMousePoint = me.curPoints[0]; var curMouseTarget = me.curPointsTarget[0]; if ( //这几个事件触发过来,是一定需要检测 curMouseTarget 的 _.indexOf(['mousedown', 'mouseover', 'click'], e.type) > -1 && !curMouseTarget) { if (!curMouseTarget) { var obj = root.getObjectsUnderPoint(curMousePoint, 1)[0]; if (obj) { me.curPointsTarget = [obj]; } } curMouseTarget = me.curPointsTarget[0]; } //mousedown的时候 如果 curMouseTarget.dragEnabled 为true。就要开始准备drag了 if (e.type == "mousedown") { //如果curTarget 的数组为空或者第一个为false ,,, if (curMouseTarget && curMouseTarget.dragEnabled) { //鼠标事件已经摸到了一个 me._touching = true; } } if (e.type == "mouseup" || e.type == "mouseout" && !contains(root.view, e.toElement || e.relatedTarget)) { if (me._draging == true) { //说明刚刚在拖动 me._dragEnd(e, curMouseTarget, 0); curMouseTarget.fire("dragend"); } me._draging = false; me._touching = false; } if (e.type == "mouseout") { if (!contains(root.view, e.toElement || e.relatedTarget)) { me.__getcurPointsTarget(e, curMousePoint, true); } } else if (e.type == "mousemove") { //|| e.type == "mousedown" ){ //拖动过程中就不在做其他的mouseover检测,drag优先 if (me._touching && e.type == "mousemove" && curMouseTarget) { //说明正在拖动啊 if (!me._draging) { //begin drag curMouseTarget.fire("dragstart"); //有可能该child没有hover style if (!curMouseTarget._globalAlpha) { curMouseTarget._globalAlpha = curMouseTarget.context.$model.globalAlpha; } curMouseTarget.context.globalAlpha = 0; //然后克隆一个副本到activeStage var cloneObject = me._clone2hoverStage(curMouseTarget, 0); cloneObject.context.globalAlpha = curMouseTarget._globalAlpha; } else { //drag move ing me._dragIngHander(e, curMouseTarget, 0); } me._draging = true; } else { //常规mousemove检测 //move事件中,需要不停的搜索target,这个开销挺大, //后续可以优化,加上和帧率相当的延迟处理 me.__getcurPointsTarget(e, curMousePoint); } } else { //其他的事件就直接在target上面派发事件 var child = curMouseTarget; if (!child) { child = root; } me.__dispatchEventInChilds(e, [child]); me._cursorHander(child); } if (root.preventDefault || e._preventDefault) { //阻止默认浏览器动作(W3C) if (e && e.preventDefault) { e.preventDefault(); } else { window.event.returnValue = false; } } }, //notInRootView 真正的mouseout,鼠标已经不在图表的节点内了 __getcurPointsTarget: function __getcurPointsTarget(e, point, notInRootView) { var me = this; var root = me.canvax; var oldObj = me.curPointsTarget[0]; if (oldObj && !oldObj.context) { oldObj = null; } var e = new Event(e); if (e.type == "mousemove" && oldObj && oldObj._hoverClass && oldObj.hoverClone && oldObj.pointChkPriority && oldObj.getChildInPoint(point)) { //小优化,鼠标move的时候。计算频率太大,所以。做此优化 //如果有target存在,而且当前元素正在hoverStage中,而且当前鼠标还在target内,就没必要取检测整个displayList了 //开发派发常规mousemove事件 e.target = e.currentTarget = oldObj; e.point = oldObj.globalToLocal(point); oldObj.dispatchEvent(e); return; } var obj = notInRootView ? null : root.getObjectsUnderPoint(point, 1)[0]; if (oldObj && oldObj != obj || e.type == "mouseout") { if (oldObj && oldObj.context) { me.curPointsTarget[0] = null; e.type = "mouseout"; e.toTarget = obj; e.target = e.currentTarget = oldObj; e.point = oldObj.globalToLocal(point); oldObj.dispatchEvent(e); } } if (obj && oldObj != obj) { me.curPointsTarget[0] = obj; e.type = "mouseover"; e.fromTarget = oldObj; e.target = e.currentTarget = obj; e.point = obj.globalToLocal(point); obj.dispatchEvent(e); } if (e.type == "mousemove" && obj) { e.target = e.currentTarget = oldObj; e.point = oldObj.globalToLocal(point); oldObj.dispatchEvent(e); } me._cursorHander(obj, oldObj); }, _cursorHander: function _cursorHander(obj, oldObj) { if (!obj && !oldObj) { this._setCursor("default"); } if (obj && oldObj != obj && obj.context) { this._setCursor(obj.context.$model.cursor); } }, _setCursor: function _setCursor(cursor) { if (this._cursor == cursor) { //如果两次要设置的鼠标状态是一样的 return; } this.canvax.view.style.cursor = cursor; this._cursor = cursor; }, /* * 原生事件系统------------------------------------------------end */ /* *第三方库的事件系统------------------------------------------------begin *触屏事件处理函数 * */ __libHandler: function __libHandler(e) { var me = this; var root = me.canvax; root.updateViewOffset(); // touch 下的 curPointsTarget 从touches中来 //获取canvax坐标系统里面的坐标 me.curPoints = me.__getCanvaxPointInTouchs(e); if (!me._draging) { //如果在draging的话,target已经是选中了的,可以不用 检测了 me.curPointsTarget = me.__getChildInTouchs(me.curPoints); } if (me.curPointsTarget.length > 0) { //drag开始 if (me.drag.start.indexOf(e.type) > -1) { //dragstart的时候touch已经准备好了target, curPointsTarget 里面只要有一个是有效的 //就认为drags开始 _.each(me.curPointsTarget, function (child, i) { if (child && child.dragEnabled) { //只要有一个元素就认为正在准备drag了 me._draging = true; //有可能该child没有hover style if (!child._globalAlpha) { child._globalAlpha = child.context.$model.globalAlpha; } me._clone2hoverStage(child, i); //先把本尊给隐藏了 child.context.globalAlpha = 0; child.fire("dragstart"); return false; } }); } if (me.drag.move.indexOf(e.type) > -1) { if (me._draging) { _.each(me.curPointsTarget, function (child, i) { if (child && child.dragEnabled) { me._dragIngHander(e, child, i); } }); } } if (me.drag.end.indexOf(e.type) > -1) { if (me._draging) { _.each(me.curPointsTarget, function (child, i) { if (child && child.dragEnabled) { me._dragEnd(e, child, 0); child.fire("dragend"); } }); me._draging = false; } } me.__dispatchEventInChilds(e, me.curPointsTarget); } else { //如果当前没有一个target,就把事件派发到canvax上面 me.__dispatchEventInChilds(e, [root]); } }, //从touchs中获取到对应touch , 在上面添加上canvax坐标系统的x,y __getCanvaxPointInTouchs: function __getCanvaxPointInTouchs(e) { var me = this; var root = me.canvax; var curTouchs = []; _.each(e.point || e.touches, function (touch) { curTouchs.push({ x: 'x' in touch ? touch.x : $.pageX(touch) - root.viewOffset.left, y: 'y' in touch ? touch.y : $.pageY(touch) - root.viewOffset.top }); }); return curTouchs; }, __getChildInTouchs: function __getChildInTouchs(touchs) { var me = this; var root = me.canvax; var touchesTarget = []; _.each(touchs, function (touch) { touchesTarget.push(root.getObjectsUnderPoint(touch, 1)[0]); }); return touchesTarget; }, /* *第三方库的事件系统------------------------------------------------end */ /* *@param {array} childs * */ __dispatchEventInChilds: function __dispatchEventInChilds(e, childs) { if (!childs && !("length" in childs)) { return false; } var me = this; _.each(childs, function (child, i) { if (child) { var ce = new Event(e); //ce.target = ce.currentTarget = child || this; ce.stagePoint = me.curPoints[i]; ce.point = child.globalToLocal(ce.stagePoint); child.dispatchEvent(ce); } }); }, //克隆一个元素到hover stage中去 _clone2hoverStage: function _clone2hoverStage(target, i) { var me = this; var root = me.canvax; var _dragDuplicate = root._bufferStage.getChildById(target.id); if (!_dragDuplicate) { _dragDuplicate = target.clone(true); _dragDuplicate._transform = target.getConcatenatedMatrix(); /** *TODO: 因为后续可能会有手动添加的 元素到_bufferStage 里面来 *比如tips *这类手动添加进来的肯定是因为需要显示在最外层的。在hover元素之上。 *所有自动添加的hover元素都默认添加在_bufferStage的最底层 **/ root._bufferStage.addChildAt(_dragDuplicate, 0); } _dragDuplicate.context.globalAlpha = target._globalAlpha; target._dragPoint = target.globalToLocal(me.curPoints[i]); return _dragDuplicate; }, //drag 中 的处理函数 _dragIngHander: function _dragIngHander(e, target, i) { var me = this; var root = me.canvax; var _point = target.globalToLocal(me.curPoints[i]); //要对应的修改本尊的位置,但是要告诉引擎不要watch这个时候的变化 target._noHeart = true; var _moveStage = target.moveing; target.moveing = true; target.context.x += _point.x - target._dragPoint.x; target.context.y += _point.y - target._dragPoint.y; target.fire("draging"); target.moveing = _moveStage; target._noHeart = false; //同步完毕本尊的位置 //这里只能直接修改_transform 。 不能用下面的修改x,y的方式。 var _dragDuplicate = root._bufferStage.getChildById(target.id); _dragDuplicate._transform = target.getConcatenatedMatrix(); //worldTransform在renderer的时候计算 _dragDuplicate.worldTransform = null; //setWorldTransform都统一在render中执行,这里注释掉 //_dragDuplicate.setWorldTransform(); //直接修改的_transform不会出发心跳上报, 渲染引擎不制动这个stage需要绘制。 //所以要手动出发心跳包 _dragDuplicate.heartBeat(); }, //drag结束的处理函数 //TODO: dragend的还需要处理end的点是否还在元素上面,要恢复hover状态 _dragEnd: function _dragEnd(e, target, i) { var me = this; var root = me.canvax; //_dragDuplicate 复制在_bufferStage 中的副本 var _dragDuplicate = root._bufferStage.getChildById(target.id); _dragDuplicate && _dragDuplicate.destroy(); target.context.globalAlpha = target._globalAlpha; } }; var event = { Event: Event, Dispatcher: Dispatcher, Handler: Handler, Manager: Manager, types: types }; /** * Canvax * * @author 释剑 (李涛, litao.lt@alibaba-inc.com) * * | a | c | tx| * | b | d | ty| * | 0 | 0 | 1 | * * @class * @memberof PIXI * * * Matrix 矩阵库 用于整个系统的几何变换计算 */ var Matrix = function Matrix(a, b, c, d, tx, ty) { this.a = a != undefined ? a : 1; this.b = b != undefined ? b : 0; this.c = c != undefined ? c : 0; this.d = d != undefined ? d : 1; this.tx = tx != undefined ? tx : 0; this.ty = ty != undefined ? ty : 0; this.array = null; }; Matrix.prototype = { concat: function concat(mtx) { var a = this.a; var c = this.c; var tx = this.tx; this.a = a * mtx.a + this.b * mtx.c; this.b = a * mtx.b + this.b * mtx.d; this.c = c * mtx.a + this.d * mtx.c; this.d = c * mtx.b + this.d * mtx.d; this.tx = tx * mtx.a + this.ty * mtx.c + mtx.tx; this.ty = tx * mtx.b + this.ty * mtx.d + mtx.ty; return this; }, concatTransform: function concatTransform(x, y, scaleX, scaleY, rotation) { var cos = 1; var sin = 0; if (rotation % 360) { var r = rotation * Math.PI / 180; cos = Math.cos(r); sin = Math.sin(r); } this.concat(new Matrix(cos * scaleX, sin * scaleX, -sin * scaleY, cos * scaleY, x, y)); return this; }, rotate: function rotate(angle) { //目前已经提供对顺时针逆时针两个方向旋转的支持 var cos = Math.cos(angle); var sin = Math.sin(angle); var a = this.a; var c = this.c; var tx = this.tx; if (angle > 0) { this.a = a * cos - this.b * sin; this.b = a * sin + this.b * cos; this.c = c * cos - this.d * sin; this.d = c * sin + this.d * cos; this.tx = tx * cos - this.ty * sin;