zoukankan      html  css  js  c++  java
  • 封装构造函数,用canvas写饼状图和柱状图

    封装构造函数,用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,
    				 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',
    				 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',
    		 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,
    			 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,
    			 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,
    			 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,
    		 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',
    			 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',
    			 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',
    			 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>
  • 相关阅读:
    这可能是全网最轻量级、对MVVM支持最好、可定制性最高的开源WPF Chart控件了
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(五)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(四)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(三)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(二)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(一)
    深入理解.NET/WPF内存泄漏
    Cocos2d-X3.0 刨根问底(九)----- 场景切换(TransitionScene)源码分析
    Cocos2d-X3.0 刨根问底(八)----- 场景(Scene)、层(Layer)相关源码分析
    Cocos2d-X3.0 刨根问底(七)----- 事件机制Event源码分析
  • 原文地址:https://www.cnblogs.com/DCL1314/p/7886427.html
Copyright © 2011-2022 走看看