基于VML与HTML5 Canva实现的跨浏览器饼图与折线图

本来想自己做个库的,毅力不够啊,所以放出源代码

当前实现的框架功能有:

1. 支持IE6+以上版本,支持Chrome, 支持FireFox

2. 动画加载机制

3. tooltip支持

4. legend支持

5. 功能丰富的参数设置

当前支持的图形种类有两种:饼图与折线图,将来也许会不定期更新,不断完善!

希望还有点毅力和时间做话。不废话啦,直接上效果图:

基于VML与HTML5 Canva实现的跨浏览器饼图与折线图_第1张图片

折线图演示代码:





Line Demo
	


VML Line Chart Demo

饼图演示代码:




My Demo 1
	


farchart - Pie Demo

JS库源代码:有兴趣者可以自己添加更多图表支持
// farchart farchart.js version 0.0.1, 28 August 2013 

// (c) 2013 by Jia ZhiGang. All Rights reserved. 
// Copyright (c) 2013 Jia ZhiGang (http://www.edinme.com)
//
// far chart is freely distributable under the terms of an GPL-style license.
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the farchart web site: http://www.edinme.com
function check_vmlCapability() {
	if(document.namespaces['v']==null) {
		var e=["shape","shapetype","group","background","path","formulas","handles","fill","stroke","shadow","textbox","textpath","imagedata","line","polyline","curve","roundrect","oval","rect","arc","image"],s=document.createStyleSheet(); 
		for(var i=0; i 0 ) 
   {
	   // If Internet Explorer, return version number
	   return parseInt (ua.substring (msie+5, ua.indexOf (".", msie )));	   
   }      
   else
   {
		// If another browser, return 0	   
		return 0;
	}                
}

var fishChart = {
	type: "null", // global flag, default
    width: 600,
    height: 400,
    series: [],
    unit: "kg",
    container: null,
	title: {
		text: "Far Chart",
		x: -100 // center offset
	},
    isIE: true,
    legend : {
    	enable : true
    },
    edge : {
    	width: 50, // for pie
    	height: 50, // for pie
		left: 50, // for other plot
		upper: 40,
		bottom: 40,
		right: 60
    },
	yAxis: {
		title: "Y Axis",
		vgap: 0,
		plotHeight: 0,
		min: 0,
		max: 0,
		tickSize: 10,
		padding: 5
	},
	xAxis: {
		categories: [],
		tickSize : 10,
		autoTick:true,
		xgap : 0,
		min:0,
		max:0,
		title:"X Axis"
	},
    animation: {
    	enable: true,
    	hh: 1,
		animCanvas:null,
		pctx: null
    },
    tooltip: {
    	enable: true,
    	tooltipCanvas : null,
    	ttContext: null,
    	index: -1
    },
    circle : { // for pie
    	cx: 0,
    	cy: 0,
    	radius: 0
    	
    },
    text : { // for pie
    	enable: false,
    	content:[]
    },
    
	point : { // for line and scatter plot
		enable : true,
		radius : 4
	},
    
    initSettings: function (config) {
    	this.type = config.type;
    	this.container = config.container;
        this.width = config.width;
        this.height = config.height;
        this.series = config.series;
        this.title.text = config.title;
        this.unit = config.unit;
        
        // tool-tip, animation, legend setting data
        if(config.tooltip != undefined) {
        	this.tooltip.enable = config.tooltip.enable;        	
        }
        if(config.animation != undefined) {
        	this.animation.enable = config.animation.enable;        	
        }
        if(config.legend != undefined) {
        	this.legend.enable = config.legend.enable;        	
        }
        if(config.text != undefined) {
        	this.text.enable = config.text.enable;
        }
        
        // edge setting data
        if(config.edge != undefined && config.edge.right != undefined) {
        	this.edge.right = config.edge.right;        	
        }
        if(config.edge != undefined && config.edge.left != undefined) {
        	this.edge.left = config.edge.left;        	
        }
        if(config.edge != undefined && config.edge.bottom != undefined) {
        	this.edge.bottom = config.edge.bottom;        	
        }
        if(config.edge != undefined && config.edge.upper != undefined) {
        	this.edge.upper = config.edge.upper;        	
        }
        
        // xAxis setting
        if(config.xAxis != undefined) {        	
        	this.xAxis.title= config.xAxis.title;
        	this.xAxis.tickSize = config.xAxis.tickSize;
        }
        
        if(config.xAxis != undefined && config.xAxis.categories != undefined) {
        	this.xAxis.categories = config.xAxis.categories;
        }
        
        // yAxis setting
        if(config.yAxis != undefined) {
        	this.yAxis.title = config.yAxis.title;
        	this.yAxis.tickSize = config.yAxis.tickSize;        	
        } 
        
        // decide whether render plot using HTML5 Canvas or VML
        if(msieversion() == 0) {
        	this.chartCanvas = document.createElement("canvas");
        	this.chartCanvas.id = "fc_canvas";
        	this.container.appendChild(this.chartCanvas);
        	this.chartCanvas.width = config.width;
        	this.chartCanvas.height = config.height;
        	this.isIE = false;
        } else {
        	check_vmlCapability();
        	this.isIE = true;
        }
    },
    
    render : function() {    	
    	var ctx = this.getCanvasContext();
    	this.renderBorder(ctx);
    	if(this.type === "pie") {
        	// initialization circle
        	this.circle.cx = this.width/2;
        	this.circle.cy = this.height/2;
        	this.circle.radius = Math.min(this.width/2, this.height/2) - Math.max(this.edge.width, this.edge.height);
        	if(this.circle.radius <= 0) {
        		console.log("Can not reader the chart, Circle is too small.");
        		return;
        	}
        	
        	// draw each arc according to data series 
        	var sum = 0;
        	var nums = this.series.length;
        	for(var i=0; i (this.circle.radius+50)) ? 50 : (this.circle.cx - this.circle.radius);
    	for(var i=0; i index) ? this.text.content[index] : this.series[index].name + ": " + (precent * 100).toFixed(0) + "%";
        		ctx.font = '10pt Calibri';
        		ctx.fillStyle="black";
        		ctx.fillText(tipStr, textPos, hy);
        	}
    	}
    },
    
    showLineTooltips : function(loc, ctx) {
    	if(!this.tooltip.enable) {
    		return;
    	}
    	var size = this.series[0].data.length;
    	var plotwidth = this.width - this.edge.left - this.edge.right;
		var deltax = (plotwidth/ size);
    	var xunit = ((loc.x - this.edge.left)/deltax); //: */loc.x - this.edge.left;
    	var deltay = this.height - this.edge.bottom - loc.y;
    	if(xunit > 0 && deltay > 0) {
    		var value = deltay/this.yAxis.ygap + this.yAxis.min;
    		var xindex = Math.floor(xunit);
    		var xpoint = xunit - xindex;
    		if(xpoint < 0.55 && xpoint >0.45) {
    			var num = this.series.length;
    			var distance = [];
    			for(var i=0; i distance[i]) {
    					min = distance[i];
    					yindex = i;
    				}
    			}
    			
    			if(this.series[yindex].data[xindex] > Math.floor(value - 3) && this.series[yindex].data[xindex] < Math.floor(value + 3) ) {
    				this.renderLineTooltips(ctx, yindex, xindex, loc);
    			} 
    			// clear tool tip
    			else {
    				this.clearTooltips(ctx);
    			}
    		} 
    		else {
    			this.clearTooltips(ctx);
    		}
    	} 
    	else {
    		this.clearTooltips(ctx);
    	}
    },
    
    renderLineTooltips : function(ctx, yindex, xindex, loc) {
		// show tool tip
		this.clearTooltips(ctx);
		if(this.tooltip.tooltipCanvas == null) {
			this.tooltip.tooltipCanvas = document.createElement("canvas");
			this.tooltip.ttContext = this.tooltip.tooltipCanvas.getContext("2d");
    		this.tooltip.tooltipCanvas.width = 150;
    		this.tooltip.tooltipCanvas.height = 100;
		}
		var m_context = this.tooltip.ttContext;
		m_context.save();
		m_context.clearRect(0, 0, this.tooltip.tooltipCanvas.width, this.tooltip.tooltipCanvas.height);
		m_context.lineWidth = 2;
		m_context.strokeStyle = this.series[yindex].color;
		m_context.fillStyle="RGBA(255,255,255,0.7)";
		this.getRoundRect(m_context, 2,2,this.tooltip.tooltipCanvas.width-4, this.tooltip.tooltipCanvas.height-4, 5, true, true);
		m_context.font="14px Arial";
		m_context.fillStyle="RGBA(0,0,0,1)";
		if(this.type == "line") {
			m_context.fillText((this.xAxis.title + ": " + this.xAxis.categories[xindex]), 5, 20);
			m_context.fillText(this.series[yindex].name + ": " + this.series[yindex].data[xindex], 5, 40);			
		} else {
			m_context.fillText(this.series[yindex].name, 5, 20);
			m_context.fillText(this.xAxis.title + ":" + this.series[yindex].data[xindex][0], 5, 40);
			m_context.fillText(this.yAxis.title + ":" + this.series[yindex].data[xindex][1], 5, 60);
		}
		m_context.restore();
		
		// make tool-tip rectangle is always visible 
		if((loc.x + this.tooltip.tooltipCanvas.width)> this.width) {
			loc.x = loc.x - this.tooltip.tooltipCanvas.width;
		}
		if((loc.y - this.tooltip.tooltipCanvas.height) <= 0) {
			loc.y = loc.y + this.tooltip.tooltipCanvas.height;
		}
		ctx.drawImage(this.tooltip.tooltipCanvas, 0, 0, this.tooltip.tooltipCanvas.width, this.tooltip.tooltipCanvas.height, 
				loc.x, loc.y-this.tooltip.tooltipCanvas.height, this.tooltip.tooltipCanvas.width, this.tooltip.tooltipCanvas.height);
    },
    
    showPieTooltips : function(loc, ctx) {
    	if(!this.tooltip.enable) {
    		return;
    	}
    	var dx = loc.x - this.width/2;
    	var dy = loc.y - this.height/2;
    	var dis = Math.floor(Math.sqrt(dx * dx + dy * dy));
    	if(dis <= this.circle.radius) {
    		// draw tool tip text
    		var angle = Math.atan2(dy,dx);
    		if(angle <= 0) {
    			// if[-Math.PI, 0], make it[Math.PI, 2*Math.PI]
    			angle = angle + 2*Math.PI;
    		}
    		
        	var sum = 0;
        	var nums = this.series.length;
        	for(var s=0; s this.width) {
				loc.x = loc.x - this.tooltip.tooltipCanvas.width;
			}
			if((loc.y - this.tooltip.tooltipCanvas.height) <= 0) {
				loc.y = loc.y + this.tooltip.tooltipCanvas.height;
			}
			ctx.drawImage(this.tooltip.tooltipCanvas, 0, 0, this.tooltip.tooltipCanvas.width, this.tooltip.tooltipCanvas.height, 
					loc.x, loc.y-this.tooltip.tooltipCanvas.height, this.tooltip.tooltipCanvas.width, this.tooltip.tooltipCanvas.height);	
    	} else {
    		this.tooltip.index = -1;
    		this.clearTooltips(ctx);
    	}
    },
    
    redrawPie : function(ctx) {
    	if(this.animation.enable) {
    		ctx.clearRect(0,0,this.width, this.height);
    		this.renderBorder(ctx);
    		ctx.drawImage(this.animation.animCanvas, 0, 0, this.width, this.height, 0, 0, this.width, this.height); 
    	} else {
        	// draw each arc according to data series 
        	var sum = 0;
        	var nums = this.series.length;
        	for(var i=0; i 5px
	    	if (typeof pattern === "undefined") {
	    		pattern = 5;
	    	}
	
	    	// calculate the delta x and delta y
	    	var dx = (toX - fromX);
	    	var dy = (toY - fromY);
	    	var distance = Math.floor(Math.sqrt(dx*dx + dy*dy));
	    	var dashlineInteveral = (pattern <= 0) ? distance : (distance/pattern);
	    	var deltay = Math.floor((dy/distance) * pattern);
	    	var deltax = Math.floor((dx/distance) * pattern);
	    	
	    	// draw dash line
	    	ctx.beginPath();
	    	for(var dl=0; dl

你可能感兴趣的:(基于VML与HTML5 Canva实现的跨浏览器饼图与折线图)