本来想自己做个库的,毅力不够啊,所以放出源代码
当前实现的框架功能有:
1. 支持IE6+以上版本,支持Chrome, 支持FireFox
2. 动画加载机制
3. tooltip支持
4. legend支持
5. 功能丰富的参数设置
当前支持的图形种类有两种:饼图与折线图,将来也许会不定期更新,不断完善!
希望还有点毅力和时间做话。不废话啦,直接上效果图:
折线图演示代码:
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