chartx
Version:
Data Visualization Chart Library
616 lines (594 loc) • 23 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
var _group = _interopRequireDefault(require("./group"));
var _index = _interopRequireDefault(require("../index"));
var _canvax = require("canvax");
var _tools = require("../../../utils/tools");
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2.default)(o), (0, _possibleConstructorReturn2.default)(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2.default)(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
//假如用户传入的是和 堆叠柱状图一样的 二维数组的field [ [uv, uv_bottom], pv ] 这样的,
//那么就 只保留uv作为field, 第二个数据作为 bottom field, 其他的多余的删除掉
//然后,bottomFieldMap中用field的uv作为key,bottom的field作为值,传给group来绘制起点
var bottomFieldMap = {},
bottomFieldDataMap = {};
var phasedLineGraphs = /*#__PURE__*/function (_GraphsBase) {
function phasedLineGraphs(opt, app) {
var _this;
(0, _classCallCheck2.default)(this, phasedLineGraphs);
_this = _callSuper(this, phasedLineGraphs, [opt, app]);
_this.type = "phasedLine";
_this.enabledField = null;
_this.groups = []; //群组集合
_canvax._.extend(true, _this, (0, _tools.getDefaultProps)(phasedLineGraphs.defaultProps()), opt);
_this.init();
return _this;
}
(0, _inherits2.default)(phasedLineGraphs, _GraphsBase);
return (0, _createClass2.default)(phasedLineGraphs, [{
key: "init",
value: function init() {
this._paramData = this.app.dataFrame.data.reduce(function (map, cur) {
map[cur.field] = cur.data;
return map;
}, {});
var phasedOpts = [this._opt];
if (_canvax._.isFunction(this.phasePoints)) {
this.phasePoints = this.phasePoints(this._paramData);
}
if (Array.isArray(this.phasePoints)) {
phasedOpts = this.splitPhases();
}
this.phasedOpts = phasedOpts;
}
// 把配置对象拆分成多个,每个对应一个phase
}, {
key: "splitPhases",
value: function splitPhases() {
var _opt$line;
var me = this;
var phaseNum = this.phasePoints.length + 1,
opt = _canvax._.clone(this._opt);
var phasedOpts = new Array(phaseNum).fill().map(function (_) {
return {
field: opt.field,
yAxisAlign: opt.yAxisAlign,
compareXValue: opt.compareXValue
};
});
['type', 'field', 'yAxisAlign', 'phasePoints', 'compareXValue', 'color'].forEach(function (key) {
delete opt[key];
});
function _setPhasedOpt(opt) {
var prePath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var _loop = function _loop(key) {
var cfg = opt[key];
if (Object.prototype.toString.call(cfg) === '[object Object]') {
_setPhasedOpt(cfg, prePath + key + '.');
return 0; // continue
}
if (_canvax._.isFunction(cfg)) {
cfg = cfg(me.phasePoints, me._paramData);
}
if (Array.isArray(cfg)) {
cfg.forEach(function (item, i) {
(0, _tools.set)(phasedOpts[i], prePath + key, item);
});
return 0; // continue
}
phasedOpts.forEach(function (phasedOpt) {
(0, _tools.set)(phasedOpt, prePath + key, cfg);
});
},
_ret;
for (var key in opt) {
_ret = _loop(key);
if (_ret === 0) continue;
}
}
_setPhasedOpt(opt);
var hexToLineargradientType = ((_opt$line = opt.line) === null || _opt$line === void 0 ? void 0 : _opt$line.hexToLineargradientType) || 'all';
phasedOpts.forEach(function (phasedOpt, idx) {
phasedOpt.type = 'line';
if (idx > 0 && idx < phaseNum - 1) phasedOpt.line.hexToLineargradientType = 'none';else if (idx == 0) phasedOpt.line.hexToLineargradientType = ['all', 'left'].includes(hexToLineargradientType) ? 'left' : 'none';else phasedOpt.line.hexToLineargradientType = ['all', 'right'].includes(hexToLineargradientType) ? 'right' : 'none';
});
return phasedOpts;
}
}, {
key: "draw",
value: function draw(opt) {
!opt && (opt = {});
this.width = opt.width;
this.height = opt.height;
_canvax._.extend(true, this.origin, opt.origin);
this.sprite.context.x = this.origin.x;
this.sprite.context.y = this.origin.y;
this.data = this._trimGraphs();
this._setGroupsForYfield(this.data, null, opt);
if (this.animation && !opt.resize) {
this.grow();
} else {
this.fire("complete");
}
return this;
}
}, {
key: "resetData",
value: function resetData(dataFrame, dataTrigger, opt) {
var _dataTrigger$comp;
var me = this;
if (dataFrame) {
me.dataFrame = dataFrame;
}
;
if (opt) {
if ('origin' in opt) {
if ('x' in opt.origin) this.sprite.context.x = opt.origin.x;
if ('y' in opt.origin) this.sprite.context.y = opt.origin.y;
}
}
me.data = me._trimGraphs();
if ((dataTrigger === null || dataTrigger === void 0 ? void 0 : (_dataTrigger$comp = dataTrigger.comp) === null || _dataTrigger$comp === void 0 ? void 0 : _dataTrigger$comp.name) == 'coord') {
me.groups.forEach(function (g) {
var _bottomFieldDataMap$g;
g.resetData(me.data[g.field].data[g.iPhase], dataTrigger, opt, (_bottomFieldDataMap$g = bottomFieldDataMap[g.field]) === null || _bottomFieldDataMap$g === void 0 ? void 0 : _bottomFieldDataMap$g[g.iPhase]);
});
} else {
var newGroups = this._setGroupsForYfield(me.data, null, opt);
newGroups.forEach(function (g) {
g._grow(null, false);
});
}
}
}, {
key: "setEnabledField",
value: function setEnabledField() {
//要根据自己的field,从enabledFields中根据enabled数据,计算一个enabled版本的field子集
this.enabledField = this.app.getComponent({
name: 'coord'
}).filterEnabledFields(this.field);
}
//dataFrame
}, {
key: "_trimGraphs",
value: function _trimGraphs() {
var me = this;
var _coord = this.app.getComponent({
name: 'coord'
});
//{"uv":{}.. ,"ppc": "pv":]}
//这样按照字段摊平的一维结构
var tmpData = {};
me.setEnabledField();
_canvax._.each(_canvax._.flatten(me.enabledField), function (field, i) {
var fieldConfig = _coord.getFieldConfig(field);
var color = fieldConfig.color;
//单条line的全部data数据
var _lineData = me.dataFrame.getFieldData(field);
if (!_lineData) return;
var _graphsData = [];
var _phaseData = [];
for (var b = 0, bl = _lineData.length; b < bl; b++) {
var rowData = me.dataFrame.getRowDataAt(b);
//返回一个和value的结构对应的point结构{x: y: }
var point = _coord.getPoint({
iNode: b,
field: field,
value: {
//x:
y: _lineData[b]
}
});
var node = {
type: "line",
iGroup: i,
// iPhase : phaseIdx,
iNode: b,
field: field,
value: _lineData[b],
x: point.pos.x,
y: point.pos.y,
rowData: rowData
// color : _.isArray(color) ? color[phaseIdx] : color //默认设置皮肤颜色,动态的在group里面会被修改
};
_phaseData.push(node);
}
;
var xValues = _phaseData.map(function (node) {
return node.rowData.xfield;
});
// 计算每个分段对应的数据节点
var phasePointIdxs = me.phasePoints.map(function (phasePoint) {
return xValues.findLastIndex(function (v) {
return me.compareXValue(v, phasePoint) <= 0;
});
});
_canvax._.each(phasePointIdxs, function (idx, i) {
if (idx == -1) {
_graphsData.push([]);
} else {
_graphsData.push(_phaseData.slice(Math.max(phasePointIdxs[i - 1] + 1 || 0, 0), idx + 1));
}
});
var lastIdx = phasePointIdxs.slice(-1)[0];
_graphsData.push(_phaseData.slice(lastIdx + 1));
// 每个分段加入前后相邻节点,用于连接处的线段平滑
var phase_start = _graphsData.findIndex(function (_data) {
return _data.length > 0;
}),
phase_end = _graphsData.findLastIndex(function (_data) {
return _data.length > 0;
});
if (phase_end - phase_start >= 1) {
_graphsData = _graphsData.map(function (phaseData, i) {
var _data = phaseData;
if (_data.length <= 0) return [];
if (i < phase_end) {
_data = _data.concat(_graphsData[i + 1].slice(0, 1).map(function (o) {
return _canvax._.clone(o);
}));
}
if (i > phase_start) {
_data = _graphsData[i - 1].slice(-2).map(function (o) {
return _canvax._.clone(o);
}).concat(_data);
}
return _data;
});
}
tmpData[field] = {
yAxis: fieldConfig.yAxis,
field: field,
data: _graphsData
};
// 河流图
var _bottomField = bottomFieldMap[field];
if (_bottomField) {
var _bottomData = me.dataFrame.getFieldData(_bottomField);
var _graphsData_bottom = [],
_phaseData_bottom = [];
for (var _b = 0, _bl = _bottomData.length; _b < _bl; _b++) {
var _node = {
iNode: _b,
field: field,
value: {
//x:
y: _bottomData[_b]
}
};
_phaseData_bottom.push(_node);
}
// 计算每个分段对应的数据节点
_canvax._.each(phasePointIdxs, function (idx, i) {
if (idx == -1) {
_graphsData_bottom.push([]);
} else {
_graphsData_bottom.push(_phaseData_bottom.slice(Math.max(phasePointIdxs[i - 1] + 1 || 0, 0), idx + 1));
}
});
_graphsData_bottom.push(_phaseData_bottom.slice(lastIdx + 1));
// 每个分段加入前后相邻节点,用于连接处的线段平滑
if (phase_end - phase_start >= 1) {
_graphsData_bottom = _graphsData_bottom.map(function (phaseData, i) {
var _data = phaseData;
if (_data.length <= 0) return [];
if (i < phase_end) {
_data = _data.concat(_graphsData_bottom[i + 1].slice(0, 1).map(function (o) {
return _canvax._.clone(o);
}));
}
if (i > phase_start) {
_data = _graphsData_bottom[i - 1].slice(-2).map(function (o) {
return _canvax._.clone(o);
}).concat(_data);
}
return _data;
});
}
bottomFieldDataMap[field] = _graphsData_bottom;
}
});
return tmpData;
}
/**
* 生长动画
*/
}, {
key: "grow",
value: function grow(callback) {
var gi = 0;
var gl = this.groups.length;
var me = this;
_canvax._.each(this.groups, function (g) {
g._grow(function () {
gi++;
callback && callback(g);
if (gi == gl) {
me.fire("complete");
}
});
});
return this;
}
//field 可以是单个 field 也可以是fields数组
}, {
key: "show",
value: function show(field) {
var _this2 = this;
this.data = this._trimGraphs();
//先把现有的group resetData
this.groups.forEach(function (g) {
g.resetData(_this2.data[g.field].data[g.iPhase]);
});
//然后把field添加到groups里面去
var newGroups = this._setGroupsForYfield(this.data, field);
newGroups.forEach(function (g) {
g._grow();
});
}
}, {
key: "hide",
value: function hide(field) {
var me = this;
var visiblePhaseNum = this.data[field].data.filter(function (d) {
return d.length > 0;
}).length;
var i = me.getGroupIndex(field);
if (i > -1) {
this.groups.splice(i, visiblePhaseNum).forEach(function (g) {
g.destroy();
});
//return; //这里不能直接return,和上面的show一样,同样的属于过渡优化,因为这个时候y轴的值域可能变了, 其他的graphs需要重新绘制
}
;
if (bottomFieldMap[field]) {
var fieldConfig = me.app.getComponent({
name: 'coord'
}).getFieldConfig(field);
fieldConfig.yAxis.resetSection();
}
this.data = this._trimGraphs();
this.groups.forEach(function (g) {
g.resetData(me.data[g.field].data[g.iPhase]);
});
}
}, {
key: "getGroupIndex",
value: function getGroupIndex(field) {
var ind = -1;
for (var i = 0, l = this.groups.length; i < l; i++) {
if (this.groups[i].field === field) {
ind = i;
break;
}
}
return ind;
}
}, {
key: "getGroup",
value: function getGroup(field) {
var groupIdx = this.getGroupIndex(field),
visiblePhaseNum = this.data[field].data.length;
return this.groups.slice(groupIdx, groupIdx + visiblePhaseNum);
}
}, {
key: "_setGroupsForYfield",
value: function _setGroupsForYfield(data, fields, opt) {
var me = this;
!opt && (opt = {});
if (fields) {
//如果有传入field参数,那么就说明只需要从data里面挑选指定的field来添加
//一般用在add()执行的时候
fields = _canvax._.flatten([fields]);
}
var _flattenField = _canvax._.flatten([this.field]);
var newGroups = [],
callbacks = [];
_canvax._.each(data, function (g, field) {
if (fields && _canvax._.indexOf(fields, field) == -1) {
//如果有传入fields,但是当前field不在fields里面的话,不需要处理
//说明该group已经在graphs里面了
return;
}
;
var fieldConfig = me.app.getComponent({
name: 'coord'
}).getFieldConfig(field);
var color = fieldConfig.color;
//iGroup 是这条group在本graphs中的ind,而要拿整个图表层级的index,就是fieldMap.ind
var iGroup = _canvax._.indexOf(_flattenField, field);
var phase_start = g.data.findIndex(function (_data) {
return _data.length > 0;
}),
phase_end = g.data.findLastIndex(function (_data) {
return _data.length > 0;
});
g.data.forEach(function (_data, iPhase) {
var _bottomFieldDataMap$f;
var phasedOpt = me.phasedOpts[iPhase];
var preGroup = me.groups.find(function (_g) {
return iGroup == _g.iGroup && iPhase == _g.iPhase;
});
if (_data.length <= 0) {
if (preGroup) {
me.groups.splice(me.groups.indexOf(preGroup), 1);
preGroup.destroy();
}
return;
}
var clip_start, clip_end;
// 偏移0.5px,这样不同phase的相交处节点就只会落在一个phase中,不会显示多个重叠的label
if (_data.length > 1) {
clip_start = _data[1].x - 0.5;
clip_end = _data.slice(-2)[0].x - 0.5;
}
if (iPhase === phase_start || g.data[iPhase - 1].length <= 2) {
clip_start = _data[0].x;
}
if (iPhase === phase_end) {
clip_end = _data.slice(-1)[0].x;
}
var bottomFieldData = (_bottomFieldDataMap$f = bottomFieldDataMap[field]) === null || _bottomFieldDataMap$f === void 0 ? void 0 : _bottomFieldDataMap$f[iPhase];
var group;
if (preGroup) {
preGroup.resetData(_data, {
comp: true
}, {
clip_start: clip_start,
clip_end: clip_end
}, bottomFieldData);
group = preGroup;
} else {
var insert = false;
group = new _group.default(_objectSpread(_objectSpread({}, fieldConfig), {}, {
color: _canvax._.isArray(color) ? color[iPhase] : color
}),
// groupIdx, //不同于fieldMap.ind
iGroup,
// me._opt,
phasedOpt, me.ctx, me.height, me.width, me, bottomFieldMap, bottomFieldData, iPhase, clip_start, clip_end);
// 插入到正确的位置,比较顺序为:field->iGroup->iPhase
var gi = Math.max(me.getGroupIndex(field), 0),
gl = me.groups.length;
for (; gi < gl; gi++) {
if (field != me.groups[gi].field) break;
if (iGroup <= me.groups[gi].iGroup && iPhase < me.groups[gi].iPhase) {
me.groups.splice(gi, 0, group);
me.sprite.addChildAt(group.sprite, gi);
insert = true;
break;
}
}
;
if (!insert) {
me.groups.splice(gi, 0, group);
me.sprite.addChildAt(group.sprite, gi);
}
group.draw({
animation: me.animation,
isResize: opt.resize
}, _data);
newGroups.push(group);
}
});
var _bottomField = bottomFieldMap[field];
if (_bottomField) {
callbacks.push(function () {
return fieldConfig.yAxis.addValToSection(me.dataFrame.getFieldData(_bottomField));
});
}
});
// 等所有field对应的groups都都添加完之后,再将bottomField的数据添加到y轴,统一执行resetData
callbacks.forEach(function (cb) {
return cb();
});
return newGroups;
}
/**获取data中和ind最接近的nodeData */
}, {
key: "getNodesAt",
value: function getNodesAt(ind, e) {
var _nodesInfoList = []; //节点信息集合
_canvax._.each(this.groups, function (group) {
var node = group.getNodeInfoAt(ind, e);
if (node && !_nodesInfoList.some(function (n) {
return n.field === node.field;
})) {
_nodesInfoList.push(node);
}
});
return _nodesInfoList;
}
/**获取x像素位置上的nodeData,如果这个值不在data中,则会构建一个 */
}, {
key: "getNodesOfPos",
value: function getNodesOfPos(x) {
var _nodesInfoList = []; //节点信息集合
_canvax._.each(this.groups, function (group) {
var node = group.getNodeInfoOfX(x);
// 相同field,不同phase的交界处node去重
if (node && !_nodesInfoList.some(function (n) {
return n.field === node.field;
})) {
_nodesInfoList.push(node);
}
});
return _nodesInfoList;
}
}, {
key: "getNodesOfXVal",
value: function getNodesOfXVal(xVal) {}
}, {
key: "tipsPointerOf",
value: function tipsPointerOf(e) {
this.groups.forEach(function (group) {
group.tipsPointerOf(e);
});
}
}, {
key: "tipsPointerHideOf",
value: function tipsPointerHideOf(e) {
this.groups.forEach(function (group) {
group.tipsPointerHideOf(e);
});
}
}], [{
key: "defaultProps",
value: function defaultProps() {
return {
field: {
detail: '字段配置,支持二维数组格式,第二维用于绘制河流图',
default: null
},
color: {
detail: '主题色,支持二维数组格式,第一维是分段,第二维是field',
default: null
},
yAxisAlign: {
detail: '绘制在哪根y轴上面',
default: 'left'
},
phasePoints: {
detail: '分段点配置,支持数组或返回数组的函数',
// 每个点对应一个x轴value,通过==判断是否开启下一分段
default: null
},
compareXValue: {
detail: 'x轴数值大小比较函数',
default: function _default(a, b) {
return a - b;
}
},
_props: [_group.default]
};
}
}, {
key: "polyfill",
value: function polyfill(opt) {
if (Array.isArray(opt.field)) {
opt.field.forEach(function (item) {
if (Array.isArray(item) && item.length > 1) {
//说明这个是一个河流图,[ [uv, uv_bottom] ] 这样的,
var bottomField = item[1];
item.length = 1;
bottomFieldMap[item[0]] = bottomField;
}
});
}
return opt;
}
}]);
}(_index.default);
_index.default.registerComponent(phasedLineGraphs, 'graphs', 'phasedLine');
var _default2 = exports.default = phasedLineGraphs;