封装构造函数,用canvas写饼状图和柱状图
封装函数
// 场景
function XDLScence( options ) {
this.stage = options.stage;
//执行场景的初始化
this.init = options.init || XDLScence.voidFn;
//执行场景的进场动画
this.pre = options.pre || XDLScence.voidFn;
//执行场景的出场动画
this.post = options.post || XDLScence.voidFn;
this.layers = options.layers || [new Konva.Layer()];
this.name = options.name || '';
this.init();
}
XDLScence.prototype = {
constructor: XDLScence,
voidFn: function() {},
CurrentScence: null,
//场景要进入舞台,只需要调用场景的 play方法。
play: function () {
var _this = this;
// doPre,
var doPre = function doPre() {
// stage.add(_this.layer);// 把当前层添加到舞台
_this.layers.forEach(function( val ){
_this.stage.add( val );
});
XDLScence.currentScene = _this;
_this.pre();
};
//如果不是第一个场景,先执行当前场景的出场动画,然后执行下一个场景的入场动画
//需要在场景的post方法中执行传进去的 next 方法。
if (XDLScence.currentScene) {
//执行上一个场景的出场动画
XDLScence.currentScene.post(doPre);
} else {
//如果是第一个场景直接执行入场动画
doPre();
}
}// play
};
//=============>S=============柱状图数据demo
// var data = [{
// name: '百度', value: .2, color: 'lightgreen'
// },{
// name: '阿里', value: .4, color: 'lightgreen'
// },{
// name: '新浪', value: .1, color: 'lightgreen'
// },{
// name: '搜狐', value: .1, color: 'lightgreen'
// },{
// name: '360', value: .2, color: 'lightgreen'
// }];
//柱状图构造函数
function Histogram(option) {
this.group = new Konva.Group({
x: option.x,
y: option.y
});
this.init(option);
}
//柱状图的原型对象
Histogram.prototype = {
constructor: Histogram,
init: function( option ) {
option.data = option.data || [];
//底线的宽度
option.blWidth = option.blWidth || 2;
option.blColor = option.blColor || 'lightgreen';
option.width = option.width || 200;
option.height = option.height || 200;
option.fontSize = option.fontSize || 12;
//把最高的柱状图的高度换算成 柱状图要求的高度。
var maxValue = 0;
for(var i = 0; i < option.data.length; i++ ) {
maxValue = maxValue > option.data[i].value ? maxValue : option.data[i].value;
}
option.height = option.height / maxValue;
//创建底线
var bottomLine = new Konva.Line({
strokeWidth: option.blWidth,
stroke: option.blColor,
points: [ 0, 0, option.width, 0 ],
lineCap: 'round',
lineJoin: 'round'
});
this.group.add( bottomLine );
//rectWidth
var rectAllWidth = option.width / option.data.length;
for(var i = 0; i < option.data.length; i++ ) {
var tempData = option.data[i];
//创建每个柱状图
var rect = new Konva.Rect({
x: rectAllWidth * (1/4 + i),
y: -1 * (option.height * tempData.value) - 1/2*option.blWidth,
width: 1/2 * rectAllWidth,
height: option.height * tempData.value,
fill: tempData.color,
shadowBlur: 5,
shadowColor: tempData.color,
// shadowOffset: {x : 10, y : 10},
shadowOpacity: 0.5,
opacity: .5,
name: 'histogramRect',
cornerRadius: 5
});
//创建 柱状图百分比文本
var text = new Konva.Text({
x: rectAllWidth * i,
y: -1 * (option.height * tempData.value) - 1/2*option.blWidth - option.fontSize -3,
fontSize: option.fontSize,
fill: tempData.color,
fontFamily: '微软雅黑',
text: tempData.value * 100 + '%',
name: 'txt',
width: rectAllWidth,
align: 'center'
});
//创建 柱状图名字文本
var nameText = new Konva.Text({
x: rectAllWidth * (1/2 + i),
y: option.blWidth + 3,
fontSize: option.fontSize,
fill: tempData.color,
fontFamily: '微软雅黑',
text: tempData.name,
rotation: 30
});
this.group.add( rect );
this.group.add( text );
this.group.add( nameText );
}
},
playAnimate: function() {
this.group.to({
duration: .1,
opacity: 1
});
this.group.find('.histogramRect').each(function( value, index ) {
var oldY = value.y();
var oldHeight = value.height();
value.y(0);
value.height(0);
value.to({
duration: .8,
y: oldY,
height: oldHeight,
opacity: .9
});
});
this.group.find(".txt").each(function(val){
var oldY = val.y();
val.y(0);
val.opacity(.1);
val.to({
duration: .8,
y: oldY,
opacity: 1
});
});
},
addToGroupOrLayer: function( group ) {
group.add(this.group);
}
};
/*
使用案例dmeo:
var data = [{
name: '阿里', value: .2, color: 'lightgreen'
},{
name: '百度', value: .4, color: 'red'
},{
name: '新浪', value: .1, color: 'blue'
},{
name: '盛大', value: .1, color: '#8E8E38'
},{
name: '360', value: .2, color: 'purple'
}];
var his = new Histogram({
data: data,
x: 1/8 * stage.width(),
y: 3/4 * stage.height(),
blWidth: 2,
blColor: 'lightblue',
width: 3/4 * stage.width(),
height: 1 * stage.height(),
fontSize: 14
});
his.addToGroupOrLayer(layer);
layer.draw();
his.playAnimate();
layer.on('click',function(){
his.playAnimate();
});
*/
//=============>E 柱状图=============
//=============>S 进度条=============
function ProgressBar(option) {
this.group = new Konva.Group({
x: option.x,
y: option.y
});
this.maxWidth = option.width;
this.drawLayer = null;
this.init(option);
}
ProgressBar.prototype = {
constructor: ProgressBar,
init: function( option ) {
var innerRect = new Konva.Rect({
x: 0,
y: 0,
width: 0,
height: option.height,
fill: option.fillColor,
name: 'innerRect',
cornerRadius: 1/2 * option.height
});
this.group.add( innerRect );
var outerRect = new Konva.Rect({
x: 0,
y: 0,
width: option.width,
height: option.height,
strokeWidth: option.strokeWidth,
stroke: option.strokeColor,
name: 'outerRect',
cornerRadius: 1/2 * option.height
});
this.group.add( outerRect );
var drawText = new Konva.Text({
text: '努力加载中:0%',
x: this.maxWidth / 2 - 14 * 3,
y: -outerRect.height(),
fontSize: 14,
fontStyle: 'bold',
fontFamily: '微软雅黑',
align: 'center',
name: 'txt'
});
this.group.add( drawText );
},
addToLayerOrGroup: function( layer ) {
layer.add( this.group );
this.drawLayer = layer;
},
changeValue: function( val ) {
if(val > 1) {
val /= 100;
}
var rect = this.group.findOne(".innerRect");
// rect.width(this.maxWidth * val);
rect.to({
duration: .2,
width: this.maxWidth * val
});
var txt = this.group.findOne('.txt');
txt.text( '努力加载中:' + Number(val).toFixed(2) * 100 + '%');
this.drawLayer.batchDraw();
},
pre: function() {
var tween = new Konva.Tween({
node: this.group,
// scaleX: 1.2,
// scaleY: 1.2,
duration: .5,
opacity: .8,
onFinish: function() {
}
});
tween.play();
}
};
/*
使用方法:
var bgLayer = new Konva.Layer();
var progressBar = new ProgressBar({
x: stage.width() / 8,
y: stage.height() / 2,
width: stage.width() * 3/4,
height: stage.height() / 20,
fillColor: '#cdcd00',
strokeColor: '#e0ffff',
strokeWidth: 6
});
progressBar.addToLayerOrGroup(bgLayer);
stage.add(bgLayer);
bgLayer.batchDraw();
progressBar.changeValue(.56);
*/
//=============>E 进度条=============
//=============>S 加载动画=============
function LoadingAnimate( option ) {
this.loadingGroup = null;
this.circleArr = [];
//初始化动画组件
this.init( option );
}
LoadingAnimate.prototype = {
constructor: LoadingAnimate,
init: function( option ) {
option.radius = option.radius || 30;
option.cenX = option.cenX;
option.cenY = option.cenY;
option.colors = option.colors || ["orange", "lightgreen", "lightblue"];
option.duration = option.duration || 1;
option.opactiy = option.opacity || .6;
option.scaleRange = option.scaleRange || .2;
this.loadingGroup = new Konva.Group({
x: option.cenX,
y: option.cenY
});
// var colors = ["orange", "lightgreen", "lightblue"];
for( var i = 0; i < 3; i++ ) {
var tempCircle = new Konva.Circle({
x: ( i-1 ) * option.radius * 2,
y: 0,
fill: colors[i],
radius: option.radius
});
this.loadingGroup.add(tempCircle);
this.circleArr[i] = tempCircle;
}
},
//把动画加载到层中
addToLayerOrGroup: function( layer ) {
layer.add( this.loadingGroup );
},
//开始动画
playAnimate: function() {
var c1 = this.circleArr[0];
var c3 = this.circleArr[2];
var _this = this;
c1.setZIndex(2);
c3.setZIndex(0);
c1.to({
duration: .8,
x: 2 * c1.radius(),
y: 0,
opacity: .8,
scaleY: 1.2,
scaleX: 1.2,
onFinish : function() {
c1.setZIndex(0);
c1.to({
duration: .8,
x: - 2 * c1.radius(),
y: 0,
opacity: .8,
scaleY: 1,
scaleX: 1,
});
}
});
c3.to({
duration: .8,
x: - 2 * c3.radius(),
y: 0,
opacity: .8,
scaleY: .8,
scaleX: .8,
onFinish : function() {
c3.setZIndex(2);
c3.to({
duration: .8,
x: 2 * c3.radius(),
y: 0,
opacity: .8,
scaleY: 1,
scaleX: 1,
onFinish: function() {
_this.playAnimate();
}
});
}
});
}
};
/*
使用方法:
var loadingDemo2 = new LoadingAnimate({
radius: 40,
cenX: 100,
cenY: 300,
colors: ["orange", "lightgreen", "lightblue"],
duration: 1,
opacity: .8,
scaleRange: .3
});
loadingDemo2.addToLayerOrGroup(layer);
loadingDemo2.playAnimate();
*/
//=============>E 加载动画=============
//=============>S 饼状图=============
function PieChart(option) {
var _this = this;
if( !option ) {
throw new Error('请初始化饼状图的参数');
}
this.animageIndex = 0;
this.playAnimateCallee = null;
this.group = null;
this.txtGroup = null;
this.animateDuration = .8;
this.outerCircle = null;
this.data = null;
this.init(option);//初始化
}
PieChart.prototype = {
constructor: PieChart,
init: function(option) {
//饼状图数据:[{name:'',value:.2,color:'red'},...]
option.data = option.data || [];
//动画执行的时间
option.animateDuration = option.animateDuration || .8;
this.animateDuration = option.animateDuration;
//动画执行的效果
option.easing = option.easing || Konva.Easings.Linear;
//x,y坐标
option.x = option.x || 0;
option.y = option.y || 0;
//饼状图半径
option.radius = option.radius === 0 ? 0 : option.radius || 100;
option.txtAwayFromWedge = option.txtAwayFromWedge || 20;
this.data = option.data;
//扇区的组
this.group = new Konva.Group({
x: option.x,
y: option.y
});
//文字的组
this.txtGroup = new Konva.Group({
x: option.x,
y: option.y
});
//默认的旋转角度
var tempAngel = -90;
//遍历生成所有扇形的对象
for(var i = 0; i < option.data.length; i++ ) {
var wedgeAngel = option.data[i].value * 360;
var wedge = new Konva.Wedge({
x: 0,
y: 0,
radius: option.radius,
fill: option.data[i].color,
angle: 0,//后面有计算出角度放到数组中
opacity: .6,
id: option.data[i].name,
name: wedgeAngel + '',
rotation: tempAngel,
visible: true
});
this.group.add(wedge);
//当前 扇形的对象 和扇形的需要旋转的角度
// arr.push({value: wedge, angle: option.data[i].value * 360});
//绘制 文字
//扇形区域的中间
var rotationAngle = 0;
var totalAngle = tempAngel + 1/2 * wedgeAngel;
//设置文字的x坐标
var txtX = Math.cos( totalAngle * Math.PI / 180) * (option.radius + option.txtAwayFromWedge);
// 设置文字的y坐标
var txtY = Math.sin( totalAngle * Math.PI / 180) * (option.radius + option.txtAwayFromWedge);
var txtTitle = option.data[i].name +' ' + option.data[i].value * 100 + '%';
var txt = new Konva.Text({
x: txtX,
y: txtY,
fill: option.data[i].color,
fontSize: '16px',
fontFamily: '微软雅黑',
fontStyle: 'bold',
align: 'left',
id: 'txt_' + option.data[i].name,
text: txtTitle,
rotation: rotationAngle,
visible: false //默认隐藏
});
this.txtGroup.add(txt);
//下面这段代码是根据 文字的位置设置一下文字的距离原型的位置
if( totalAngle > 90 && totalAngle < 270 ) {
// rotationAngle = -30;
txt.x( txt.x()-txt.getWidth() );
}
//设置下一个元素旋转到具体的位置
tempAngel += option.data[i].value * 360;
}
// 绘制外圆
this.outerCircle = new Konva.Circle({
stroke: '#a0a0a0',
strokeWidth: 1,
radius: option.radius + 5,
x: option.x,
y: option.y
});
},
//展示动画
playAnimate: function() {
_this = this;
if(this.animageIndex >= this.data.length) {
_this.animageIndex = 0;
return;
}
//先初始化到0的状态,然后进行绘制。
if(this.animageIndex == 0) {
_this.group.getChildren().each(function(value, index){
value.angle(0);
});
_this.txtGroup.getChildren().each(function(value,index){
value.hide();
});
}
this.playAnimateCallee= arguments.callee;//当前函数
//绘制一个 扇区的动画
var wedge = this.group.getChildren()[this.animageIndex];
var angel = Number(wedge.name());//扇区的度数
wedge.to({
angle: angel,
duration: angel * this.animateDuration / 360,
onFinish: function() {
_this.txtGroup.getChildren()[_this.animageIndex].show();
_this.txtGroup.getParent().draw();
_this.animageIndex++;
_this.playAnimateCallee();//调用当前函数自身,形成动画队列。
}
});
},
//把当前 饼状图添加到 层
addToLayer: function(layer) {
layer.add(this.group);
layer.add(this.txtGroup);
layer.add(this.outerCircle);
layer.draw();
},
};
/*
用法:
//饼状图数据
var data = [{
name: "前端",
value: .25,
color: 'lightblue'
},{
name: "php",
value: .2,
color: 'orange'
},{
name: "UI",
value: .3,
color: 'blue'
},{
name: "C++",
value: .05,
color: 'green'
},{
name: "游戏",
value: .1,
color: 'purple'
},{
name: "Java",
value: .1,
color: 'red'
}];
//创建饼状图
var pieChart = new PieChart({
data: data,//扇形区域的数据
animateDuration: 2,//扇形动画的时间
easing: Konva.Easings.EaseIn,//扇形动画的速度规格
x: cenX,
y: cenY,
radius: .14 * stage.width(),//半径
txtAwayFromWedge: .2 * .14 * stage.width()//扇形上的文字的距离圆形的距离
});
pieChart.addToLayer(layer);
pieChart.playAnimate();
layer.draw();
layer.on('click tap', function(){
pieChart.playAnimate();
});
*/
//=============E 饼状图=============
饼状图
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>饼状图</title>
<style>
body {
padding: 0;
margin: 0;
background-color: #f0f0f0;
overflow: hidden;
}
</style>
<script src="./konva.js"></script>
<script src="./KonvaExtend.js"></script>
</head>
<body>
<div id="container">
</div>
<script>
//创建舞台
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,//全屏
height: window.innerHeight
});
//创建层
var layer = new Konva.Layer();
stage.add(layer);
//中心点坐标
var cenX = stage.width() / 2;
var cenY = stage.height() / 2;
//创建加载层动画
//饼状图数据
var data = data = [
{name:"apple", value:0.24, color:"pink"},
{name:"三星", value:0.26, color:"skyblue"},
{name:"华为", value:0.13, color:"orange"},
{name:"锤子", value:0.17, color:"#333"},
{name:"小米", value:0.08, color:"purple"},
{name:"其他", value:0.12, color:"cyan"}
];
//创建饼状图
var maxSize = stage.width() > stage.height() ? stage.height() : stage.width();
var pieChart = new PieChart({
data: data,//扇形区域的数据
animateDuration: 2,//扇形动画的时间
easing: Konva.Easings.EaseIn,//扇形动画的速度规格
x: cenX,
y: cenY,
radius: .3 * maxSize,//半径
txtAwayFromWedge: .3 * .3 * maxSize//扇形上的文字的距离圆形的距离
});
pieChart.addToLayer(layer);
pieChart.playAnimate();
layer.draw();
layer.on('click tap', function(){
pieChart.playAnimate();
});
</script>
</body>
</html>
柱状图
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>柱状图</title>
<style>
body {
padding: 0;
margin: 0;
background-color: #f0f0f0;
overflow: hidden;
}
</style>
<script src="./konva.js"></script>
<script src="./KonvaExtend.js" charset="utf-8"></script>
</head>
<body>
<div id="container">
</div>
<script>
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
var layer = new Konva.Layer();
stage.add(layer);
var cenX = stage.width() / 2;
var cenY = stage.height() / 2;
var data = [
{ name: '百度', value: 2, color: 'blue' },
{ name: '阿里', value: 4, color: 'red' },
{ name: '新浪', value: 1, color: 'purple' },
{ name: '搜狐', value: 1, color: 'navy' },
{ name: '兄弟连', value: 2, color: 'orange' }
];
var his = new Histogram({
data: data,
x: 1/8 * stage.width(),
y: 3/4 * stage.height(),
blWidth: 2,
blColor: 'lightblue',
width: 3/4 * stage.width(),
height: 1/3 * stage.height(),
fontSize: 14
});
his.addToGroupOrLayer(layer);
layer.draw();
his.playAnimate();
layer.on('click',function(){
his.playAnimate();
});
</script>
</body>
</html>