chartx
Version:
Data Visualization Chart Library
893 lines (860 loc) • 27.9 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _canvax = require("canvax");
var _dataSection = _interopRequireDefault(require("./dataSection"));
var _tools = require("../utils/tools");
//TODO 所有的get xxx OfVal 在非proportion下面如果数据有相同的情况,就会有风险
var axis = /*#__PURE__*/function () {
function axis(opt, dataOrg) {
(0, _classCallCheck2.default)(this, axis);
//源数据
//这个是一个一定会有两层数组的数据结构,是一个标准的dataFrame数据
// [
// [
// [1,2,3],
// [1,2,3] //这样有堆叠的数据只会出现在proportion的axis里,至少目前是这样
// ]
// ,[
// [1,2,3]
// ]
// ]
this._opt = _canvax._.clone(opt);
this.dataOrg = dataOrg || [];
this._dataSectionLayout = []; //和dataSection一一对应的,每个值的pos,//get xxx OfPos的时候,要先来这里做一次寻找
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;
_canvax._.extend(true, this, (0, _tools.getDefaultProps)(axis.defaultProps()), opt);
}
return (0, _createClass2.default)(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") {
this._min = _canvax._.min(this.dataSection);
this._max = _canvax._.max(this.dataSection);
//默认情况下 origin 就是datasection的最小值
//如果用户设置了origin,那么就已用户的设置为准
if (!("origin" in this._opt)) {
this.origin = 0; //this.dataSection[0];//_.min( this.dataSection );
if (_canvax._.max(this.dataSection) < 0) {
this.origin = _canvax._.max(this.dataSection);
}
;
if (_canvax._.min(this.dataSection) > 0) {
this.origin = _canvax._.min(this.dataSection);
}
;
}
;
this._originTrans = this._getOriginTrans(this.origin);
this.originPos = this.getPosOfVal(this.origin);
}
;
//get xxx OfPos的时候,要先来这里做一次寻找
this._dataSectionLayout = [];
_canvax._.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() {
if (Array.isArray(this._opt.dataSection) && this._opt.dataSection.length) {
this.dataSection = this._opt.dataSection;
this._dataSectionGroup = [this.dataSection];
} else {
if (this.layoutType == "proportion") {
//如果像柱状图中有堆叠的情况出现, arr中已经把堆叠的数据加起来了
var arr = this._getDataSection();
if ("origin" in this._opt) {
arr.push(this._opt.origin);
}
if (arr.length == 1) {
var n = arr[0];
if (Math.abs(n) > 10) {
arr = [n - 1, n, n + 1];
} else if (Math.abs(n) >= 1 && Math.abs(n) <= 10) {
arr = [n - 0.1, n, n + 0.1];
} else {
arr = [n * .5, n, n * 2];
}
}
if (Array.isArray(this.verniers) && this.verniers.length) {
arr = arr.concat(this.verniers);
}
if (this.symmetric) {
//如果需要处理为对称数据
var _min = _canvax._.min(arr);
var _max = _canvax._.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 (_canvax._.isFunction(this.sectionHandler)) {
this.dataSection = this.sectionHandler(arr);
}
if (!this.dataSection || !this.dataSection.length) {
this.dataSection = _dataSection.default.section(arr, 3);
}
if (this.symmetric) {
//可能得到的区间是偶数, 非对称,强行补上
var _min2 = _canvax._.min(this.dataSection);
var _max2 = _canvax._.max(this.dataSection);
if (Math.abs(_min2) > Math.abs(_max2)) {
this.dataSection.push(Math.abs(_min2));
} else {
this.dataSection.unshift(-Math.abs(_max2));
}
;
}
//如果还是0
if (this.dataSection.length == 0) {
this.dataSection = [0];
}
//如果有 middleWeight 设置,就会重新设置dataSectionGroup
this._dataSectionGroup = [_canvax._.clone(this.dataSection)];
this._middleweight(); //如果有middleweight配置,需要根据配置来重新矫正下datasection
this._sort();
} else {
//非proportion 也就是 rule peak 模式下面
this.dataSection = _canvax._.flatten(this.dataOrg); //this._getDataSection();
this._dataSectionGroup = [this.dataSection];
}
;
}
;
//middleWeightPos在最后设定
this._middleWeightPos();
}
}, {
key: "_getDataSection",
value: function _getDataSection() {
//如果有堆叠,比如[ ["uv","pv"], "ppc" ]
//那么这个 this.dataOrg, 也是个对应的结构
//vLen就会等于2
var vLen = 1;
_canvax._.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 = _canvax._.flatten(this.dataOrg); //_.flatten( data.org );
var _arr = [];
for (var i = 0, il = arr.length; i < il; i++) {
if (arr[i] !== null && arr[i] !== undefined && arr[i] !== '') {
_arr.push(arr[i]);
}
}
;
return _canvax._.unique(_arr);
}
//二维的yAxis设置,肯定是堆叠的比如柱状图,
}, {
key: "_twoDimensional",
value: function _twoDimensional() {
var d = this.dataOrg;
var arr = [];
var min;
_canvax._.each(d, function (d) {
if (!d.length) {
return;
}
;
//有数据的情况下
if (!_canvax._.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 _canvax._.flatten(arr);
}
//val 要被push到datasection 中去的 值
//主要是用在markline等组件中,当自己的y值超出了yaxis的范围
}, {
key: "_addValToSection",
value: function _addValToSection(val) {
this.addVerniers(val);
this.setDataSection();
this.calculateProps();
}
}, {
key: "addVerniers",
value: function addVerniers(val) {
if (this.verniers.indexOf(val) == -1) {
this.verniers.push(val);
}
}
}, {
key: "_sort",
value: function _sort() {
if (this.sort) {
var sort = this._getSortType();
if (sort == "desc") {
this.dataSection.reverse();
//_dataSectionGroup 从里到外全部都要做一次 reverse, 这样就可以对应上 dataSection.reverse()
_canvax._.each(this._dataSectionGroup, function (dsg) {
dsg.reverse();
});
this._dataSectionGroup.reverse();
//_dataSectionGroup reverse end
}
;
}
;
}
}, {
key: "_getSortType",
value: function _getSortType() {
var _sort;
if (_canvax._.isString(this.sort)) {
_sort = this.sort;
}
if (!_sort) {
_sort = "asc";
}
return _sort;
}
}, {
key: "_middleweight",
value: function _middleweight() {
if (this.middleWeight) {
//支持多个量级的设置
if (!_canvax._.isArray(this.middleWeight)) {
this.middleWeight = [this.middleWeight];
}
;
//拿到dataSection中的min和 max 后,用middleweight数据重新设置一遍dataSection
var dMin = _canvax._.min(this.dataSection);
var dMax = _canvax._.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 (!_canvax._.isArray(this.middleWeightPos)) {
this.middleWeightPos = [this.middleWeightPos];
}
;
//需要校验下middleWeightPos中是有的值之和不能大于1
//如果大于1了则默认按照均分设置
var _count = 0;
_canvax._.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;
_canvax._.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 _this = this;
var pos = 0;
var me = this;
var dsgLen = this._dataSectionGroup.length;
var groupLength = this.axisLength / dsgLen;
var _loop = function _loop(i) {
var ds = _this._dataSectionGroup[i];
groupLength = _this.axisLength * _this.middleWeightPos[i];
var preGroupLenth = 0;
_canvax._.each(_this.middleWeightPos, function (mp, mi) {
if (mi < i) {
preGroupLenth += me.axisLength * mp;
}
;
});
if (_this.layoutType == "proportion") {
var min = _canvax._.min(ds);
var max = _canvax._.max(ds);
var amountABS = Math.abs(max - min);
if (origin >= min && origin <= max) {
pos = (origin - min) / amountABS * groupLength + preGroupLenth;
return 1; // break
}
;
} else {
/* TODO: 貌似 非proportion 布局 下面的_originTrans 没毛意义啊,先注释掉
let valInd = _.indexOf(ds , origin);
if( valInd != -1 ){
if( this.layoutType == "rule" ){
pos = valInd / (ds.length - 1) * groupLength;
};
if( this.layoutType == "peak" ){
pos = ( groupLength/ds.length ) * (valInd+1) - ( groupLength/ds.length )/2;
};
};
*/
}
};
for (var i = 0, l = dsgLen; i < l; i++) {
if (_loop(i)) 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;
_canvax._.each(props, function (_p) {
if (_p in opt) {
prop = _p;
}
});
var layoutData;
_canvax._.each(this._dataSectionLayout, function (item) {
if (item[prop] === opt[prop]) {
layoutData = item;
}
;
});
return layoutData || {};
}
}, {
key: "getPosOfVal",
value: function getPosOfVal(val) {
/* val可能会重复,so 这里得到的会有问题,先去掉
//先检查下 _dataSectionLayout 中有没有对应的记录
let _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 _this2 = this;
var me = this;
var pos;
var cellCount = this._getCellCount(); //dataOrg上面的真实数据节点数,把轴分成了多少个节点
if (this.layoutType == "proportion") {
var dsgLen = this._dataSectionGroup.length;
var _loop2 = function _loop2(i) {
var ds = _this2._dataSectionGroup[i];
var groupLength = _this2.axisLength * _this2.middleWeightPos[i];
var preGroupLenth = 0;
_canvax._.each(_this2.middleWeightPos, function (mp, mi) {
if (mi < i) {
preGroupLenth += me.axisLength * mp;
}
;
});
var min = _canvax._.min(ds);
var max = _canvax._.max(ds);
var val = "val" in opt ? opt.val : _this2.getValOfInd(opt.ind);
var _origin = _this2.origin;
var origiInRange = !(_origin < min || _origin > max);
//如果 origin 并不在这个区间
if (!origiInRange) {
_origin = min;
} else {
//如果刚好在这个区间Group
}
;
if (val >= min && val <= max) {
//origin不在区间内的话,maxGroupDisABS一定是整个区间, 也就是说这个区间的原点在起点min
var maxGroupDisABS = Math.max(Math.abs(max - _origin), Math.abs(_origin - min));
var amountABS = Math.abs(max - min);
var originPos = maxGroupDisABS / amountABS * groupLength;
pos = (val - _origin) / maxGroupDisABS * originPos + preGroupLenth;
if (isNaN(pos)) {
pos = parseInt(preGroupLenth);
}
;
if (origiInRange) {
//origin在区间内的时候,才需要偏移_originTrans
pos += _this2._originTrans;
}
;
} else {
//先简单处理下超出边界的行为
if (val > max && i == l - 1) {
pos = me.axisLength;
}
if (val < min && i == 0) {
pos = 0;
}
}
};
for (var i = 0, l = dsgLen; i < l; i++) {
_loop2(i);
}
} else {
if (cellCount == 1) {
//如果只有一数据,那么就全部默认在正中间
pos = this.axisLength / 2;
} else {
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));
return parseInt(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的索引
let org = ds ? ds : _.flatten(this.dataOrg);
return org[ind];
};
*/
}
//这里的ind
}, {
key: "_getValOfInd",
value: function _getValOfInd(ind) {
var me = this;
var org = _canvax._.flatten(this.dataOrg);
var val;
if (this.layoutType == "proportion") {
//let dsgLen = this._dataSectionGroup.length;
//let groupLength = this.axisLength / dsgLen;
_canvax._.each(this._dataSectionGroup, function (ds, i) {
var groupLength = me.axisLength * me.middleWeightPos[i];
var preGroupLenth = 0;
_canvax._.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 = _canvax._.min(ds);
var max = _canvax._.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 _this3 = this;
var valInd = -1;
if (this.layoutType == "proportion") {
//先检查下 _dataSectionLayout 中有没有对应的记录
var _ind = this._getLayoutDataOf({
val: val
}).ind;
if (_ind != undefined) {
return _ind;
}
;
//因为在proportion中index 就是 pos
//所以这里要返回pos
valInd = this.getPosOfVal(val);
} else {
var jsonOrgItem = this._coord.app.dataFrame.jsonOrg.find(function (row) {
return row[_this3.field] == val;
});
if (jsonOrgItem) {
valInd = jsonOrgItem.__index__ - this._coord.app.dataFrame.range.start;
}
// _.each(this.dataOrg, function (arr) {
// _.each(arr, function (list) {
// let _ind = _.indexOf(list, val);
// if (_ind != -1) {
// valInd = _ind;
// };
// });
// });
}
return valInd;
}
}, {
key: "getCellLength",
value: function getCellLength() {
if (this._cellLength !== null) {
return this._cellLength;
}
;
//ceilWidth默认按照peak算, 而且不能按照dataSection的length来做分母
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() {
return this.getCellLength();
}
//pos目前没用到,给后续的高级功能预留接口
}, {
key: "getCellLengthOfInd",
value: function getCellLengthOfInd() {
return this.getCellLength();
}
}, {
key: "_getCellCount",
value: function _getCellCount() {
if (this._cellCount !== null) {
return this._cellCount;
}
;
//总共有几个数据节点,默认平铺整个dataOrg,和x轴的需求刚好契合,而y轴目前不怎么需要用到这个
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;
}
}], [{
key: "defaultProps",
value: function defaultProps() {
return {
layoutType: {
detail: '布局方式',
default: 'proportion'
},
axisLength: {
detail: '轴长度',
default: 1
},
dataSection: {
detail: '轴数据集',
default: []
},
sectionHandler: {
detail: '自定义dataSection的计算公式',
default: null
},
verniers: {
detail: '设定的游标,dataSection的区间一定会覆盖这些值',
default: []
},
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轴的计算也必须要都是整除的'
}
};
}
}]);
}();
var _default = exports.default = axis;