UNPKG

chartx3d

Version:

Data Visualization Chart Library

1,851 lines (1,507 loc) 993 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = global || self, global.Chartx3d = factory()); }(this, function () { 'use strict'; function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 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; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 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); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _construct(Parent, args, Class) { if (isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } } function _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance"); } var _ = {}; var breaker = {}; var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.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, nativeBind = FuncProto.bind; 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')); }; //} { _.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; }; function normalizeTickInterval(interval, magnitude) { var normalized, i; // var multiples = [1, 2, 2.5, 5, 10]; var multiples = [1, 2, 5, 10]; // round to a tenfold of 1, 2, 2.5 or 5 normalized = interval / magnitude; // normalize the interval to the nearest multiple for (var i = 0; i < multiples.length; i++) { interval = multiples[i]; if (normalized <= (multiples[i] + (multiples[i + 1] || multiples[i])) / 2) { break; } } // multiply back to the correct magnitude interval *= magnitude; return interval; } function correctFloat(num) { return parseFloat(num.toPrecision(14)); } function getLinearTickPositions(arr, $maxPart, $cfg) { arr = _.without(arr, undefined, null, ""); var scale = $cfg && $cfg.scale ? parseFloat($cfg.scale) : 1; //返回的数组中的值 是否都为整数(思霏) 防止返回[8, 8.2, 8.4, 8.6, 8.8, 9] 应该返回[8, 9] var isInt = $cfg && $cfg.isInt ? 1 : 0; if (isNaN(scale)) { scale = 1; } var max = _.max(arr); var initMax = max; max *= scale; var min = _.min(arr); if (min == max) { if (max > 0) { min = 0; return [min, max]; // min= Math.round(max/2); } else if (max < 0) { return [max, 0]; //min = max*2; } else { max = 1; return [0, max]; } } var length = max - min; if (length) { var tempmin = min; //保证min>0的时候不会出现负数 min -= length * 0.05; // S.log(min +":"+ tempmin) if (min < 0 && tempmin >= 0) { min = 0; } max += length * 0.05; } var tickInterval = (max - min) * 0.3; //72 / 365; var magnitude = Math.pow(10, Math.floor(Math.log(tickInterval) / Math.LN10)); tickInterval = normalizeTickInterval(tickInterval, magnitude); if (isInt) { tickInterval = Math.ceil(tickInterval); } var pos, lastPos, roundedMin = correctFloat(Math.floor(min / tickInterval) * tickInterval), roundedMax = correctFloat(Math.ceil(max / tickInterval) * tickInterval), tickPositions = []; // Populate the intermediate values pos = roundedMin; while (pos <= roundedMax) { // Place the tick on the rounded value tickPositions.push(pos); // Always add the raw tickInterval, not the corrected one. pos = correctFloat(pos + tickInterval); // If the interval is not big enough in the current min - max range to actually increase // the loop variable, we need to break out to prevent endless loop. Issue #619 if (pos === lastPos) { break; } // Record the last value lastPos = pos; } if (tickPositions.length >= 3) { if (tickPositions[tickPositions.length - 2] >= initMax) { tickPositions.pop(); } } return tickPositions; } var dataSection = { section: function section($arr, $maxPart, $cfg) { return _.uniq(getLinearTickPositions($arr, $maxPart, $cfg)); } }; var cloneOptions = function cloneOptions(opt) { return _.clone(opt); }; var cloneData = function cloneData(data) { return JSON.parse(JSON.stringify(data)); }; var getDefaultProps = function getDefaultProps(dProps) { var target = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; for (var p in dProps) { if (!!p.indexOf("_")) { if (!dProps[p] || !dProps[p].propertys) { //如果这个属性没有子属性了,那么就说明这个已经是叶子节点了 if (_.isObject(dProps[p]) && !_.isFunction(dProps[p]) && !_.isArray(dProps[p])) { target[p] = dProps[p].default; } else { target[p] = dProps[p]; } } else { target[p] = {}; getDefaultProps(dProps[p].propertys, target[p]); } } } return target; }; var axis = /*#__PURE__*/ function () { _createClass(axis, null, [{ key: "defaultProps", value: function defaultProps() { return { layoutType: { detail: '布局方式', default: 'proportion' }, dataSection: { detail: '轴数据集', default: [] }, sectionHandler: { detail: '自定义dataSection的计算公式', default: null }, waterLine: { detail: '水位线', default: null, documentation: '水位data,需要混入 计算 dataSection, 如果有设置waterLine, dataSection的最高水位不会低于这个值' }, middleWeight: { detail: '区间分隔线', default: null, documentation: '如果middleweight有设置的话 dataSectionGroup 为被middleweight分割出来的n个数组>..[ [0,50 , 100],[100,500,1000] ]' }, middleWeightPos: { detail: '区间分隔线的物理位置,百分比,默认 0.5 ', default: null }, symmetric: { detail: '自动正负对称', default: false, documentation: 'proportion下,是否需要设置数据为正负对称的数据,比如 [ 0,5,10 ] = > [ -10, 0 10 ],象限坐标系的时候需要' }, origin: { detail: '轴的起源值', default: null, documentation: '\ 1,如果数据中又正数和负数,则默认为0 <br />\ 2,如果dataSection最小值小于0,则baseNumber为最小值<br />\ 3,如果dataSection最大值大于0,则baseNumber为最大值<br />\ 4,也可以由用户在第2、3种情况下强制配置为0,则section会补充满从0开始的刻度值\ ' }, sort: { detail: '排序', default: null }, posParseToInt: { detail: '是否位置计算取整', default: false, documentation: '比如在柱状图中,有得时候需要高精度的能间隔1px的柱子,那么x轴的计算也必须要都是整除的' } }; } }]); function axis(opt, dataOrg) { _classCallCheck(this, axis); //源数据 //这个是一个一定会有两层数组的数据结构,是一个标准的dataFrame数据 // [ // [ // [1,2,3], // [1,2,3] //这样有堆叠的数据只会出现在proportion的axis里,至少目前是这样 // ] // ,[ // [1,2,3] // ] // ] this._opt = _.clone(opt); this.dataOrg = dataOrg || []; //3d中有引用到 this.dataSectionLayout = []; //和dataSection一一对应的,每个值的pos,//get xxx OfPos的时候,要先来这里做一次寻找 //轴总长 //3d中有引用到 this.axisLength = 1; this._cellCount = null; this._cellLength = null; //数据变动的时候要置空 //默认的 dataSectionGroup = [ dataSection ], dataSection 其实就是 dataSectionGroup 去重后的一维版本 this.dataSectionGroup = []; this.originPos = 0; //value为 origin 对应的pos位置 this._originTrans = 0; //当设置的 origin 和datasection的min不同的时候, //min,max不需要外面配置,没意义 this._min = null; this._max = null; _.extend(true, this, getDefaultProps(axis.defaultProps()), opt); } _createClass(axis, [{ key: "resetDataOrg", value: function resetDataOrg(dataOrg) { //配置和数据变化 this.dataSection = []; this.dataSectionGroup = []; this.dataOrg = dataOrg; this._cellCount = null; this._cellLength = null; } }, { key: "setAxisLength", value: function setAxisLength(length) { this.axisLength = length; this.calculateProps(); } }, { key: "calculateProps", value: function calculateProps() { var me = this; if (this.layoutType == "proportion") { if (this._min == null) { this._min = _.min(this.dataSection); } if (this._max == null) { this._max = _.max(this.dataSection); } //如果用户设置了origin,那么就已用户的设置为准 if (!("origin" in this._opt)) { this.origin = 0; //this.dataSection[0];//_.min( this.dataSection ); if (_.max(this.dataSection) < 0) { this.origin = _.max(this.dataSection); } if (_.min(this.dataSection) > 0) { this.origin = _.min(this.dataSection); } } this._originTrans = this._getOriginTrans(this.origin); this.originPos = this.getPosOfVal(this.origin); } this.dataSectionLayout = []; _.each(this.dataSection, function (val, i) { var ind = i; if (me.layoutType == "proportion") { ind = me.getIndexOfVal(val); } var pos = parseInt(me.getPosOf({ ind: i, val: val }), 10); me.dataSectionLayout.push({ val: val, ind: ind, pos: pos }); }); } }, { key: "getDataSection", value: function getDataSection() { //对外返回的dataSection return this.dataSection; } }, { key: "setDataSection", value: function setDataSection(_dataSection) { var me = this; //如果用户没有配置dataSection,或者用户传了,但是传了个空数组,则自己组装dataSection if (_.isEmpty(_dataSection) && _.isEmpty(this._opt.dataSection)) { if (this.layoutType == "proportion") { var arr = this._getDataSection(); if ("origin" in me._opt) { arr.push(me._opt.origin); } if (arr.length == 1) { arr.push(arr[0] * .5); } if (this.waterLine) { arr.push(this.waterLine); } if (this.symmetric) { //如果需要处理为对称数据 var _min = _.min(arr); var _max = _.max(arr); if (Math.abs(_min) > Math.abs(_max)) { arr.push(Math.abs(_min)); } else { arr.push(-Math.abs(_max)); } } for (var ai = 0, al = arr.length; ai < al; ai++) { arr[ai] = Number(arr[ai]); if (isNaN(arr[ai])) { arr.splice(ai, 1); ai--; al--; } } if (_.isFunction(this.sectionHandler)) { this.dataSection = this.sectionHandler(arr); } if (!this.dataSection || !this.dataSection.length) { this.dataSection = dataSection.section(arr, 3); } if (this.symmetric) { //可能得到的区间是偶数, 非对称,强行补上 var _min = _.min(this.dataSection); var _max = _.max(this.dataSection); if (Math.abs(_min) > Math.abs(_max)) { this.dataSection.push(Math.abs(_min)); } else { this.dataSection.unshift(-Math.abs(_max)); } } if (this.dataSection.length == 0) { this.dataSection = [0]; } this.dataSectionGroup = [_.clone(this.dataSection)]; this._middleweight(); //如果有middleweight配置,需要根据配置来重新矫正下datasection this._sort(); } else { //非proportion 也就是 rule peak 模式下面 this.dataSection = _.flatten(this.dataOrg); //this._getDataSection(); this.dataSectionGroup = [this.dataSection]; } } else { this.dataSection = _dataSection || this._opt.dataSection; this.dataSectionGroup = [this.dataSection]; } this._middleWeightPos(); } }, { key: "_getDataSection", value: function _getDataSection() { //如果有堆叠,比如[ ["uv","pv"], "click" ] //那么这个 this.dataOrg, 也是个对应的结构 //vLen就会等于2 var vLen = 1; _.each(this.dataOrg, function (arr) { vLen = Math.max(arr.length, vLen); }); if (vLen == 1) { return this._oneDimensional(); } if (vLen > 1) { return this._twoDimensional(); } } }, { key: "_oneDimensional", value: function _oneDimensional() { var arr = _.flatten(this.dataOrg); //_.flatten( data.org ); for (var i = 0, il = arr.length; i < il; i++) { arr[i] = arr[i] || 0; } return arr; } //二维的yAxis设置,肯定是堆叠的比如柱状图,后续也会做堆叠的折线图, 就是面积图 }, { key: "_twoDimensional", value: function _twoDimensional() { var d = this.dataOrg; var arr = []; var min; _.each(d, function (d, i) { if (!d.length) { return; } if (!_.isArray(d[0])) { arr.push(d); return; } var varr = []; var len = d[0].length; var vLen = d.length; for (var i = 0; i < len; i++) { var up_count = 0; var up_i = 0; var down_count = 0; var down_i = 0; for (var ii = 0; ii < vLen; ii++) { var _val = d[ii][i]; if (!_val && _val !== 0) { continue; } min == undefined && (min = _val); min = Math.min(min, _val); if (_val >= 0) { up_count += _val; up_i++; } else { down_count += _val; down_i++; } } up_i && varr.push(up_count); down_i && varr.push(down_count); } arr.push(varr); }); arr.push(min); return _.flatten(arr); } //val 要被push到datasection 中去的 值 //主要是用在markline等组件中,当自己的y值超出了yaxis的范围 }, { key: "setWaterLine", value: function setWaterLine(val) { if (val <= this.waterLine) return; this.waterLine = val; if (val < _.min(this.dataSection) || val > _.max(this.dataSection)) { //waterLine不再当前section的区间内,需要重新计算整个datasection this.setDataSection(); this.calculateProps(); } } }, { key: "_sort", value: function _sort() { if (this.sort) { var sort = this._getSortType(); if (sort == "desc") { this.dataSection.reverse(); //dataSectionGroup 从里到外全部都要做一次 reverse, 这样就可以对应上 dataSection.reverse() _.each(this.dataSectionGroup, function (dsg, i) { dsg.reverse(); }); this.dataSectionGroup.reverse(); //dataSectionGroup reverse end } } } }, { key: "_getSortType", value: function _getSortType() { var _sort; if (_.isString(this.sort)) { _sort = this.sort; } if (!_sort) { _sort = "asc"; } return _sort; } }, { key: "_middleweight", value: function _middleweight() { if (this.middleWeight) { //支持多个量级的设置 if (!_.isArray(this.middleWeight)) { this.middleWeight = [this.middleWeight]; } var dMin = _.min(this.dataSection); var dMax = _.max(this.dataSection); var newDS = [dMin]; var newDSG = []; for (var i = 0, l = this.middleWeight.length; i < l; i++) { var preMiddleweight = dMin; if (i > 0) { preMiddleweight = this.middleWeight[i - 1]; } var middleVal = preMiddleweight + parseInt((this.middleWeight[i] - preMiddleweight) / 2); newDS.push(middleVal); newDS.push(this.middleWeight[i]); newDSG.push([preMiddleweight, middleVal, this.middleWeight[i]]); } var lastMW = this.middleWeight.slice(-1)[0]; if (dMax > lastMW) { newDS.push(lastMW + (dMax - lastMW) / 2); newDS.push(dMax); newDSG.push([lastMW, lastMW + (dMax - lastMW) / 2, dMax]); } //好了。 到这里用简单的规则重新拼接好了新的 dataSection this.dataSection = newDS; this.dataSectionGroup = newDSG; } } }, { key: "_middleWeightPos", value: function _middleWeightPos() { var me = this; if (this.middleWeightPos) { if (!_.isArray(this.middleWeightPos)) { this.middleWeightPos = [this.middleWeightPos]; } //如果大于1了则默认按照均分设置 var _count = 0; _.each(this.middleWeightPos, function (pos) { _count += pos; }); if (_count < 1) { this.middleWeightPos.push(1 - _count); } if (_count > 1) { this.middleWeightPos = null; } } if (this.middleWeight) { if (!this.middleWeightPos) { this.middleWeightPos = []; var _prePos = 0; _.each(this.middleWeight, function () { var _pos = 1 / (me.middleWeight.length + 1); _prePos += _pos; me.middleWeightPos.push(_pos); }); this.middleWeightPos.push(1 - _prePos); } } else { this.middleWeightPos = [1]; } } //origin 对应 this.origin 的值 }, { key: "_getOriginTrans", value: function _getOriginTrans(origin) { var pos = 0; var dsgLen = this.dataSectionGroup.length; //var groupLength = this.axisLength / dsgLen; for (var i = 0, l = dsgLen; i < l; i++) { var ds = this.dataSectionGroup[i]; var groupLength = this.axisLength * this.middleWeightPos[i]; var preGroupLenth = 0; _.each(this.middleWeightPos, function (mp, mi) { if (mi < i) { preGroupLenth += me.axisLength * mp; } }); if (this.layoutType == "proportion") { var min = _.min(ds); var max = _.max(ds); var amountABS = Math.abs(max - min); if (origin >= min && origin <= max) { pos = (origin - min) / amountABS * groupLength + preGroupLenth; break; } } } if (this.sort == "desc") { //如果是倒序的 pos = -(groupLength - pos); } return parseInt(pos); } //opt { val ind pos } 一次只能传一个 }, { key: "_getLayoutDataOf", value: function _getLayoutDataOf(opt) { var props = ["val", "ind", "pos"]; var prop; _.each(props, function (_p) { if (_p in opt) { prop = _p; } }); var layoutData; _.each(this.dataSectionLayout, function (item) { if (item[prop] === opt[prop]) { layoutData = item; } }); return layoutData || {}; } }, { key: "getPosOfVal", value: function getPosOfVal(val) { /* val可能会重复,so 这里得到的会有问题,先去掉 //先检查下 dataSectionLayout 中有没有对应的记录 var _pos = this._getLayoutDataOf({ val : val }).pos; if( _pos != undefined ){ return _pos; }; */ return this.getPosOf({ val: val }); } }, { key: "getPosOfInd", value: function getPosOfInd(ind) { //先检查下 dataSectionLayout 中有没有对应的记录 var _pos = this._getLayoutDataOf({ ind: ind }).pos; if (_pos != undefined) { return _pos; } return this.getPosOf({ ind: ind }); } //opt {val, ind} val 或者ind 一定有一个 }, { key: "getPosOf", value: function getPosOf(opt) { var me = this; var pos; var cellCount = this._getCellCount(); //dataOrg上面的真实数据节点数,把轴分成了多少个节点 if (this.layoutType == "proportion") { var dsgLen = this.dataSectionGroup.length; //var groupLength = this.axisLength / dsgLen; for (var i = 0, l = dsgLen; i < l; i++) { var ds = this.dataSectionGroup[i]; var groupLength = this.axisLength * this.middleWeightPos[i]; var preGroupLenth = 0; _.each(this.middleWeightPos, function (mp, mi) { if (mi < i) { preGroupLenth += me.axisLength * mp; } }); var min = _.min(ds); var max = _.max(ds); var val = "val" in opt ? opt.val : this.getValOfInd(opt.ind); if (val >= min && val <= max) { var _origin = this.origin; //如果 origin 并不在这个区间 if (_origin < min || _origin > max) { _origin = min; } var maxGroupDisABS = Math.max(Math.abs(max - _origin), Math.abs(_origin - min)); var amountABS = Math.abs(max - min); var h = maxGroupDisABS / amountABS * groupLength; pos = (val - _origin) / maxGroupDisABS * h + preGroupLenth; if (isNaN(pos)) { pos = parseInt(preGroupLenth); } break; } } } else { if (cellCount == 1) { //如果只有一数据,那么就全部默认在正中间 pos = this.axisLength / 2; } else { //TODO 这里在非proportion情况下,如果没有opt.ind 那么getIndexOfVal 其实是有风险的, //因为可能有多个数据的val一样 var valInd = "ind" in opt ? opt.ind : this.getIndexOfVal(opt.val); if (valInd != -1) { if (this.layoutType == "rule") { //line 的xaxis就是 rule pos = valInd / (cellCount - 1) * this.axisLength; } if (this.layoutType == "peak") { //bar的xaxis就是 peak /* pos = (this.axisLength/cellCount) * (valInd+1) - (this.axisLength/cellCount)/2; */ var _cellLength = this.getCellLength(); pos = _cellLength * (valInd + 1) - _cellLength / 2; } } } } !pos && (pos = 0); pos = Number(pos.toFixed(1)) + this._originTrans; return Math.abs(pos); } }, { key: "getValOfPos", value: function getValOfPos(pos) { //先检查下 dataSectionLayout 中有没有对应的记录 var _val = this._getLayoutDataOf({ pos: pos }).val; if (_val != undefined) { return _val; } return this._getValOfInd(this.getIndexOfPos(pos)); } //ds可选 }, { key: "getValOfInd", value: function getValOfInd(ind) { //先检查下 dataSectionLayout 中有没有对应的记录 var _val = this._getLayoutDataOf({ ind: ind }).val; if (_val != undefined) { return _val; } return this._getValOfInd(ind); /* if (this.layoutType == "proportion") { } else { //这里的index是直接的对应dataOrg的索引 var org = ds ? ds : _.flatten(this.dataOrg); return org[ind]; }; */ } //这里的ind }, { key: "_getValOfInd", value: function _getValOfInd(ind, ds) { var me = this; var org = _.flatten(this.dataOrg); var val; if (this.layoutType == "proportion") { var dsgLen = this.dataSectionGroup.length; //var groupLength = this.axisLength / dsgLen; _.each(this.dataSectionGroup, function (ds, i) { var groupLength = me.axisLength * me.middleWeightPos[i]; var preGroupLenth = 0; _.each(me.middleWeightPos, function (mp, mi) { if (mi < i) { preGroupLenth += me.axisLength * mp; } }); if (parseInt(ind / groupLength) == i || i == me.dataSectionGroup.length - 1) { var min = _.min(ds); var max = _.max(ds); val = min + (max - min) / groupLength * (ind - preGroupLenth); return false; } }); } else { val = org[ind]; } return val; } }, { key: "getIndexOfPos", value: function getIndexOfPos(pos) { //先检查下 dataSectionLayout 中有没有对应的记录 var _ind = this._getLayoutDataOf({ pos: pos }).ind; if (_ind != undefined) { return _ind; } var ind = 0; var cellLength = this.getCellLengthOfPos(pos); var cellCount = this._getCellCount(); if (this.layoutType == "proportion") { //proportion中的index以像素为单位 所以,传入的像素值就是index return pos; } else { if (this.layoutType == "peak") { ind = parseInt(pos / cellLength); if (ind == cellCount) { ind = cellCount - 1; } } if (this.layoutType == "rule") { ind = parseInt((pos + cellLength / 2) / cellLength); if (cellCount == 1) { //如果只有一个数据 ind = 0; } } } return ind; } }, { key: "getIndexOfVal", value: function getIndexOfVal(val) { var valInd = -1; if (this.layoutType == "proportion") { //先检查下 dataSectionLayout 中有没有对应的记录 var _ind = this._getLayoutDataOf({ val: val }).ind; if (_ind != undefined) { return _ind; } //所以这里要返回pos valInd = this.getPosOfVal(val); } else { _.each(this.dataOrg, function (arr) { _.each(arr, function (list) { var _ind = _.indexOf(list, val); if (_ind != -1) { valInd = _ind; } }); }); } return valInd; } }, { key: "getCellLength", value: function getCellLength() { if (this._cellLength !== null) { return this._cellLength; } var axisLength = this.axisLength; var cellLength = axisLength; var cellCount = this._getCellCount(); if (cellCount) { if (this.layoutType == "proportion") { cellLength = 1; } else { //默认按照 peak 也就是柱状图的需要的布局方式 cellLength = axisLength / cellCount; if (this.layoutType == "rule") { if (cellCount == 1) { cellLength = axisLength / 2; } else { cellLength = axisLength / (cellCount - 1); } } if (this.posParseToInt) { cellLength = parseInt(cellLength); } } } this._cellLength = cellLength; return cellLength; } //这个getCellLengthOfPos接口主要是给tips用,因为tips中只有x信息 }, { key: "getCellLengthOfPos", value: function getCellLengthOfPos(pos) { return this.getCellLength(); } //pos目前没用到,给后续的高级功能预留接口 }, { key: "getCellLengthOfInd", value: function getCellLengthOfInd(pos) { return this.getCellLength(); } }, { key: "_getCellCount", value: function _getCellCount() { if (this._cellCount !== null) { return this._cellCount; } var cellCount = 0; if (this.layoutType == "proportion") { cellCount = this.axisLength; } else { if (this.dataOrg.length && this.dataOrg[0].length && this.dataOrg[0][0].length) { cellCount = this.dataOrg[0][0].length; } } this._cellCount = cellCount; return cellCount; } }]); return axis; }(); /** * 把原始的数据 * field1 field2 field3 * 1 2 3 * 2 3 4 * 这样的数据格式转换为内部的 * [{field:'field1',index:0,data:[1,2]} ......] * 这样的结构化数据格式。 */ function parse2MatrixData(list) { if (list === undefined || list === null) { list = []; } if (list.length > 0 && !_.isArray(list[0])) { var newArr = []; var fields = []; var fieldNum = 0; for (var i = 0, l = list.length; i < l; i++) { var row = list[i]; if (i == 0) { for (var f in row) { fields.push(f); } newArr.push(fields); fieldNum = fields.length; } var _rowData = []; for (var ii = 0; ii < fieldNum; ii++) { _rowData.push(row[fields[ii]]); } newArr.push(_rowData); } return newArr; } else { return list; } } function dataFrame (data, opt) { //数据做一份拷贝,避免污染源数据 data = JSON.parse(JSON.stringify(data)); var dataFrame = { //数据框架集合 length: 0, org: [], //最原始的数据,一定是个行列式,因为如果发现是json格式数据,会自动转换为行列式 data: [], //最原始的数据转化后的数据格式:[o,o,o] o={field:'val1',index:0,data:[1,2,3]} getRowDataAt: _getRowDataAt, getRowDataOf: _getRowDataOf, getFieldData: _getFieldData, getDataOrg: getDataOrg, fields: [], range: { start: 0, end: 0 } }; if (!data || data.length == 0) { return dataFrame; } if (data.length > 0 && !_.isArray(data[0])) { data = parse2MatrixData(data); } dataFrame.length = data.length - 1; //设置好数据区间end值 dataFrame.range.end = dataFrame.length - 1; //然后检查opts中是否有dataZoom.range if (opt && opt.dataZoom && opt.dataZoom.range) { _.extend(dataFrame.range, opt.dataZoom.range); } if (data.length && data[0].length && !~data[0].indexOf("__index__")) { //如果数据中没有用户自己设置的__index__,那么就主动添加一个__index__,来记录元数据中的index for (var i = 0, l = data.length; i < l; i++) { if (!i) { data[0].push("__index__"); } else { data[i].push(i - 1); } } } dataFrame.org = data; dataFrame.fields = data[0] ? data[0] : []; //所有的字段集合; var total = []; //已经处理成[o,o,o] o={field:'val1',index:0,data:[1,2,3]} for (var a = 0, al = dataFrame.fields.length; a < al; a++) { var o = {}; o.field = dataFrame.fields[a]; o.index = a; o.data = []; total.push(o); } dataFrame.data = total; //填充好total的data并且把属于yAxis的设置为number for (var a = 1, al = data.length; a < al; a++) { for (var b = 0, bl = data[a].length; b < bl; b++) { var _val = data[a][b]; //如果用户传入的数据是个number,那么就转换为真正的Number吧 //‘223’ --》 223 if (!isNaN(_val) && _val !== "" && _val !== null) { _val = Number(_val); } total[b].data.push(_val); //total[b].data.push( data[a][b] ); } } function getDataOrg($field, format, totalList, lev) { if (!lev) lev = 0; var arr = totalList || total; if (!arr) { return; } if (!format) { format = function format(e) { return e; }; } function _format(data) { for (var i = 0, l = data.length; i < l; i++) { data[i] = format(data[i]); } return data; } if (!_.isArray($field)) { $field = [$field]; } var newData = []; for (var i = 0, l = $field.length; i < l; i++) { if (_.isArray($field[i])) { newData.push(getDataOrg($field[i], format, totalList, lev + 1)); } else { var _fieldData = newData; if (!lev) { _fieldData = []; } for (var ii = 0, iil = arr.length; ii < iil; ii++) { if ($field[i] == arr[ii].field) { _fieldData.push(_format(arr[ii].data.slice(dataFrame.range.start, dataFrame.range.end + 1))); break; } } if (!lev) { newData.push(_fieldData); } } } return newData; } /* * 获取某一行数据 */ function _getRowDataAt(index) { var o = {}; var data = dataFrame.data; for (var a = 0; a < data.length; a++) { o[data[a].field] = data[a].data[dataFrame.range.start + index]; } return o; } /** * obj => {uv: 100, pv: 10 ...} */ function _getRowDataOf(obj) { !obj && (obj = {}); var arr = []; var expCount = 0; for (var p in obj) { expCount++; } if (expCount) { for (var i = dataFrame.range.start; i <= dataFrame.range.end; i++) { var matchNum