UNPKG

chartx

Version:

Data Visualization Chart Library

616 lines (594 loc) 23 kB
"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;