chartx3d
Version:
Data Visualization Chart Library
1,851 lines (1,507 loc) • 993 kB
JavaScript
(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