vislite
Version:
灵活、快速、简单的数据可视化交互式跨端前端库
235 lines (218 loc) • 7.82 kB
JavaScript
/*!
* PieLayout of VISLite JavaScript Library v1.4.0
* git+https://github.com/oi-contrib/VISLite.git
*/
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
];
}
/*!
* animation of OIPage v1.3.0
* git+https://github.com/oi-contrib/OIPage.git
*/
//当前正在运动的动画的tick函数堆栈
var $timers = [];
//唯一定时器的定时间隔
var $interval = 13;
//定时器ID
var $timerId;
/**
* 动画轮播
* @param {function} doback 轮询函数,有一个形参deep,0-1,表示执行进度
* @param {number} duration 动画时长,可选
* @param {function} callback 动画结束回调,可选,有一个形参deep,0-1,表示执行进度
*
* @returns {function} 返回一个函数,调用该函数,可以提前结束动画
*/
function animation(doback, duration, callback) {
if (arguments.length < 2) duration = 400;
if (arguments.length < 3) callback = function () { };
var clock = {
//把tick函数推入堆栈
"timer": function (tick, duration, callback) {
if (!tick) {
throw new Error('Tick is required!');
}
var id = new Date().valueOf() + "_" + (Math.random() * 1000).toFixed(0);
$timers.push({
"id": id,
"createTime": new Date(),
"tick": tick,
"duration": duration,
"callback": callback
});
clock.start();
return id;
},
//开启唯一的定时器timerId
"start": function () {
if (!$timerId) {
$timerId = setInterval(clock.tick, $interval);
}
},
//被定时器调用,遍历timers堆栈
"tick": function () {
var 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()) / duration;
passTime = passTime > 1 ? 1 : passTime;
tick(passTime);
if (passTime < 1 && timer.id) {
//动画没有结束再添加
$timers.push(timer);
} else {
callback(passTime);
}
}
if ($timers.length <= 0) {
clock.stop();
}
},
//停止定时器,重置timerId=null
"stop": function () {
if ($timerId) {
clearInterval($timerId);
$timerId = null;
}
}
};
var id = clock.timer(function (deep) {
//其中deep为0-1,表示改变的程度
doback(deep);
}, duration, callback);
return {
// 一个函数
// 用于在动画结束前结束动画
stop: function () {
var i;
for (i in $timers) {
if ($timers[i].id == id) {
$timers[i].id = void 0;
return;
}
}
}
};
}
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, 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], 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[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 };