UNPKG

vislite

Version:

灵活、快速、简单的数据可视化交互式跨端前端库

273 lines (254 loc) 10 kB
function initOption(setOption, defaultOption) { for (var key in setOption) { defaultOption[key] = setOption[key]; } return defaultOption; } function rotate (cx, cy, deg, x, y) { var cos = Math.cos(deg), sin = Math.sin(deg); return [ (x - cx) * cos - (y - cy) * sin + cx, (x - cx) * sin + (y - cy) * cos + cy ]; } //当前正在运动的动画的tick函数堆栈 let $timers = []; //唯一定时器的定时间隔 let $interval = 13; //定时器ID let $timerId; /** * 动画轮播 * @param {function} doback 轮询函数,有一个形参deep,0-1,表示执行进度 * @param {number} duration 动画时长,可选 * @param {function} callback 动画结束回调,可选,有一个形参deep,0-1,表示执行进度 * * @returns {object} 返回一个对象,包含一个stop方法,用于在动画结束前结束动画 */ function animation(doback, duration, callback) { if (arguments.length < 2) duration = 400; if (arguments.length < 3) callback = function () { }; let clock = { //把tick函数推入堆栈 "timer": function (tick, duration, callback) { if (!tick) { throw new Error('Tick is required!'); } let id = new Date().valueOf() + "_" + (Math.random() * 1000).toFixed(0); $timers.push({ "id": id, "createTime": new Date(), // 开始时间 "pauseTime": -1, // 暂停的时间,继续运行的时候,借助此计算暂停的时间差 "pauseKeepTime": 0, // 暂停用去的时间 "status": "running", // running(运行中), paused(暂停中) "tick": tick, "duration": duration, "callback": callback }); clock.start(); return id; }, //开启唯一的定时器timerId "start": function () { if (!$timerId) { try { if (globalThis && globalThis.requestAnimationFrame) { $timerId = globalThis.requestAnimationFrame(function step() { clock.tick(); if ($timerId) $timerId = globalThis.requestAnimationFrame(step); }); } else { $timerId = setInterval(clock.tick, $interval); } } catch (e) { $timerId = setInterval(clock.tick, $interval); } } }, //被定时器调用,遍历timers堆栈 "tick": function () { let createTime, flag, tick, callback, timer, duration, passTime, timers = $timers; $timers = []; $timers.length = 0; for (flag = 0; flag < timers.length; flag++) { //初始化数据 timer = timers[flag]; createTime = timer.createTime; tick = timer.tick; duration = timer.duration; callback = timer.callback; //执行 passTime = (+new Date().valueOf() - createTime.valueOf() - timer.pauseKeepTime) / duration; passTime = passTime > 1 ? 1 : passTime; if (timer.status === "running") { tick(passTime); } // 只有当动画没有结束或者动画处于暂停状态时,才继续添加到timers堆栈 if ((passTime < 1 || timer.status === "paused") && timer.id) { //动画没有结束再添加 $timers.push(timer); } else { callback(passTime); } } if ($timers.length <= 0) { clock.stop(); } }, //停止定时器,重置timerId=null "stop": function () { if ($timerId) { try { if (globalThis && globalThis.requestAnimationFrame) globalThis.cancelAnimationFrame($timerId); else clearInterval($timerId); } catch (e) { clearInterval($timerId); } $timerId = null; } } }; let id = clock.timer(function (deep) { //其中deep为0-1,表示改变的程度 doback(deep); }, duration, callback); return { // 结束动画 stop: function () { for (let i in $timers) { if ($timers[i].id == id) { $timers[i].id = void 0; } } }, // 暂停动画 pause: function () { for (let i in $timers) { if ($timers[i].id == id) { if ($timers[i].pauseTime === -1) { $timers[i].pauseTime = new Date(); $timers[i].status = "paused"; } } } }, // 继续动画 resume: function () { for (let i in $timers) { if ($timers[i].id == id) { if ($timers[i].pauseTime !== -1) { $timers[i].pauseKeepTime += (new Date().valueOf() - $timers[i].pauseTime.valueOf()); $timers[i].pauseTime = -1; $timers[i].status = "running"; } } } } }; } var PieLayout = (function () { function PieLayout(config) { if (config === void 0) { config = {}; } this.name = 'PieLayout'; this.__option = { cx: 200, cy: 200, radius: [50, 100], duration: 200, }; this.__hoverIndex = -1; this.__config = initOption(config, { name: function (pieData, initPie) { return pieData.name; }, value: function (pieData, initPie) { return pieData.value; } }); } PieLayout.prototype.setOption = function (option) { initOption(option, this.__option); return this; }; PieLayout.prototype.use = function (initPie, hoverIndex) { if (hoverIndex === void 0) { hoverIndex = -1; } var pie = { count: initPie.length, cx: this.__option.cx, cy: this.__option.cy, radius: this.__option.radius, hoverIndex: hoverIndex, node: [] }; var totalValue = 0; var names = [], values = []; for (var i = 0; i < initPie.length; i++) { names[i] = this.__config.name(initPie[i], initPie); values[i] = this.__config.value(initPie[i], initPie); totalValue += values[i]; } var beginDeg = Math.PI * -0.5, currenDeg; for (var i = 0; i < initPie.length; i++) { currenDeg = values[i] / totalValue * Math.PI * 2; var radius = [this.__option.radius[0] * (1 + (this.__option.radius[0] > 0 && hoverIndex === i ? -0.1 : 0)), this.__option.radius[1] * (1 + (hoverIndex === i ? 0.05 : 0))]; var pdeg = beginDeg + currenDeg * 0.5, pradius = Math.max(this.__option.radius[0], this.__option.radius[1]); var p0 = rotate(pie.cx, pie.cy, pdeg, pie.cx + pradius, pie.cy); var p1 = rotate(pie.cx, pie.cy, pdeg, pie.cx + pradius + 15, pie.cy); var pflag = p0[0] > pie.cx ? 1 : -1; var p2 = [p1[0] + pflag * 20, p1[1]]; var p3 = [p1[0] + pflag * 25, p1[1]]; pie.node[i] = { value: values[i], name: names[i], beginDeg: beginDeg, deg: currenDeg, isHover: hoverIndex === i, radius: radius, label: { line: [p0, p1, p2], position: p3, align: pflag === -1 ? "right" : "left" } }; beginDeg += currenDeg; } return pie; }; PieLayout.prototype.bind = function (initPie, renderBack) { this.__rback = renderBack; this.__oralPie = initPie; this.__prePie = this.use(this.__oralPie, this.__hoverIndex); this.__rback(this.__prePie); return this; }; PieLayout.prototype.unbind = function () { this.__rback = function () { return null; }; this.__oralPie = null; this.__prePie = null; this.__hoverIndex = -1; return this; }; PieLayout.prototype.setHover = function (index) { if (!this.__prePie || this.__hoverIndex === index) return this; this.__hoverIndex = index; this.doUpdate(); return this; }; PieLayout.prototype.doUpdate = function () { var _this = this; var newPie = this.use(this.__oralPie, this.__hoverIndex); var cachePie = JSON.parse(JSON.stringify(newPie)); animation(function (deep) { if (_this.__prePie) { for (var i = 0; i < cachePie.count; i++) { cachePie.node[i].radius[0] = _this.__prePie.node[i].radius[0] + (newPie.node[i].radius[0] - _this.__prePie.node[i].radius[0]) * deep; cachePie.node[i].radius[1] = _this.__prePie.node[i].radius[1] + (newPie.node[i].radius[1] - _this.__prePie.node[i].radius[1]) * deep; } } _this.__rback(cachePie); }, this.__option.duration, function () { _this.__prePie = newPie; _this.__rback(_this.__prePie); }); return this; }; return PieLayout; }()); export { PieLayout as default };