【www.quanqiunao.cn--javascript】
支持 线性图 区域图 柱状图 饼图<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>smipleChart</title>
<style type="text/css">
.cc{
height:450px; width:800px; border:1px solid #999; position:relative; margin:20px;
}
</style>
</head>
<body>
<div id="t"></div>
<div id="t1">
</div>
<div id="line" class="cc"></div>
<div id="area" class="cc"></div>
<div id="zhu" class="cc"></div>
<div id="zhu1" class="cc" style="height:600px;"></div>
<div id="pie" class="cc"></div>
<div id="vv" class="cc" style="height:300px; width:520px;"></div>
<script type="text/javascript">
(function(doc,undefined){
var win = this,
hasSVG = win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1"),
isIE = /msie/i.test(navigator.userAgent) && !win.opera,
path = hasSVG?"d":"path",
seal = hasSVG?"z":"e",
math = Math,
mathRound = math.round,
mathFloor = math.floor,
mathCeil = math.ceil,
mathMax = math.max,
mathMin = math.min,
mathAbs = math.abs,
mathCos = math.cos,
mathSin = math.sin,
M = "M",
L = "L";
win.$ = function(Id){
return document.getElementById(Id);
};
win.extend = function(){
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = true, options;
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
i = 2;
}
if ( typeof target !== "object" && Object.prototype.toString.call(target)!="[object Function]")
target = {};
for(;i<length;i++){
if ( (options = arguments[ i ]) != null )
for(var name in options){
var src = target[ name ], copy = options[ name ];
if ( target === copy )
continue;
if ( deep && copy && typeof copy === "object" && !copy.nodeType ){
target[ name ] = arguments.callee( deep, src || ( copy.length != null ? [ ] : { } ), copy );
}
else if(copy !== undefined)
target[ name ] = copy;
}
}
return target;
};
win.each = function ( object, callback, args ) {
var name, i = 0, length = object.length;
if ( args ) {
args = Array.prototype.slice.call(arguments).slice(2);
if ( length === undefined ) {
for ( name in object )
if ( callback.apply( object[ name ],[name,object[ name ]].concat(args) ) === false )
break;
} else
for ( ; i < length; i++)
if ( callback.apply( object[ i ],[i,object[ i ]].concat(args)) === false ) //
break;
} else {
if ( length === undefined ) {
for ( name in object )
if ( callback.call( object[ name ], name, object[ name ] ) === false )
break;
} else
for ( var value = object[0];
i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
}
return object;
};
//---------------------------------------------------------------
function processPoint( x ){
return isIE ? ~~x.toFixed(0) : ~~x.toFixed(0) + 0.5;
};
function calTextLen(txt, cssStr){
var span = doc.createElement("span");
if(cssStr){
typeof cssStr === "string"
? span.style.cssText = cssStr
: extend(span.style,cssStr);
}else{
extend(span.style,{
fontSiz : "12px",
fontFamily : ""Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif"
});
}
span.innerHTML = txt || "";
span.style.visibility = "hidden";
doc.body.appendChild(span);
var width = span.offsetWidth,
height = span.offsetHeight;
doc.body.removeChild(span);
return {w:width,h:height};
};
function angle(r,center,o,jingdu){
var hudu = Math.PI*2*(o/360),
x = center[0]+ r*Math.sin(hudu),
y = center[1]+ -r*Math.cos(hudu);
return [x.toFixed(jingdu||0),y.toFixed(jingdu||0)];
}
function xx(a,b,lineNum){
var t = 10000;
var stf = ((b*t-a*t)/lineNum)/t,
arr = [1,2,2.5,5,10],
c = 1,
v;
// 分割线的基数是 [1,2,2.5,5,10] 这个步骤是查找 间隔 属于哪个范围
if(stf<arr[0]){
while( stf<arr[0] ){
c = c*10;
arr[0]=arr[0]/c;
}
each([1,2,2.5,5,10],function(i,o){
arr[i]= o/c;
});
}else if(stf>arr[4]){
while( stf>arr[4] ){
c = c*10;
arr[4] = arr[4]*c;
}
each([1,2,2.5,5,10],function(i,o){
arr[i]= o*c;
});
}
//上面找到间隔后 找到间隔中最接近的一个
each(arr,function(i,o){
if(stf<o){
v = o;
return false;
}
});
//a 是最小的
//b是最大 的
a = (a*t-mathAbs((a%v)*t))/t;
b = (b*t+(b%v===0?0:(v-b%v))*t)/t;
//看看还剩几条线没有画
var num = Math.max(0,lineNum - Math.round((b-a)/v));
if(a>=0){
//让图比较靠中间
/*while(num!==0){
num%2===0
? a = (a*t-v*t)/t
: b = (b*t+v*t)/t;
num--;
}*/
//坐标比较整数化
if(a!=0&&num!=0){
while(a!=0&&num!=0){
a = (a*t-v*t)/t;
num--;
if((a*t-v*num*t)/10000>0&&a%10===0)
break;
}
}
if(num!=0){
while(num!==0){
b = (b*t+v*t)/t
num--;
}
}
}else{
//让图比较靠中间
/*while(num!==0){
num%2===0
? b = (b*t+v*t)/t
: a = (a*t-v*t)/t
num--;
}*/
//坐标比较整数化
if(b<0&&num!=0){
while(b!=0&&num!=0){
b = (b*t+v*t)/t;
num--;
if((b*t+v*num*t)/t<0&&a%10===0)
break;
}
}
if(num!=0){
while(num!==0){
a = (a*t-v*t)/t
num--;
}
}
}
return {min:a,max:b,stf:v};
}
//---------------------------------------------------------------------------------------------------------------
//对svg vml元素的一些创建 修改属性 样式 删除 == 一些的操作
win.vector = function(){};
win.vector.prototype = {
$c : function(graphic,nodeName){
this.element = this[0] = doc.createElementNS("http://www.w3.org/2000/svg", nodeName);
this.graphic = graphic;
return this;
},
attr: function(hash,val){
var elem = this.element,
key,
value;
if(typeof hash === "string"){
if(val === undefined){
return elem.getAttribute(hash);
}else{
elem.setAttribute(hash, val);
return this;
}
} else {
for(key in hash){
value = hash[key];
if(key === path){
value && value.join
&&(value = value.join(" "));
/(NaN| |^$)/.test(value)
&&(value = "M 0 0");
}
elem.setAttribute(key, value)
}
}
return this;
},
css: function(hash){
var str = "";
for(var key in hash){
if(isIE && key == "opacity"){
this.element.style["filter"] = "alpha(opacity="+ hash[key] * 100+")";
}else{
this.element.style[key] = hash[key];
}
}
return this;
},
on: function(eventName, handler){
var self = this;
this.element.addEventListener(eventName,function(){
handler.call(self)
},false);
return this;
},
appendTo: function(parent){
if(parent){
parent.element
? parent.element.appendChild(this.element)
: parent.appendChild(this.element)
} else {
this.graphic.container.appendChild(this.element);
}
return this;
},
addText: function(str){
var elem = this.element;
if(elem.nodeName === "text"){
elem.appendChild(doc.createTextNode(str.toString() || " "));
}
return this;
},
setOpacity : function(v){
this.attr("fill-opacity",v)
},
toFront: function() {
this.element.parentNode.appendChild(this.element)
return this;
},
show: function(){
this.element.style.display = "block";
return this;
},
hide: function(){
this.element.style.display = "none";
return this;
}
};
//---------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------
//如果是vml修改其中的一些方法
if(!hasSVG){
//-------------创建vml环境-----------------
doc.createStyleSheet().addRule(".vml", "behavior:url(#default#VML);display:inline-block;position:absolute;left:0px;top:0px");
!doc.namespaces.vml && !+"\v1";
doc.namespaces.add("vml", "urn:schemas-microsoft-com:vml");
//-------------修改一些方法-----------------
extend(vector.prototype,{
$c : function(graphic,nodeName){
var name = nodeName || "shape";
this.element= this[0] = (name === "div" || name === "span")
? doc.createElement(name)
: doc.createElement("<vml:"+name+" class="vml">");
this.graphic = graphic;
return this;
},
on : function(eventName, handler){
var self = this;
this.element.attachEvent("on" + eventName,function(){
handler.call(self);
});
return this;
},
addText : function(txt){
var elem = this.element;
elem.innerHTML = txt || "";
return this;
},
setOpacity : function(v){
this.opacity.opacity=v;
}
});
}
//---------------------------------------------------------------------------------------------------
//画图类
//------------------------------------------------------------
win.smipleChart = function(){
this.init.apply(this,arguments);
};
smipleChart.prototype = {
options : {
charts : {
paddingRight : 20,
radius : 200,
style : {
fontFamily : ""Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif",
fontSize : "12px",
background : "#FFFFFF"
}
},
title : {
text : "",
y : 10,
style : {
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"16px",
fontWeight:"bold"
}
},
subTitle : {
text : "",
y : 30,
style : {
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px",
color: "#111"
}
},
yUnit : {
text : "",
style : {
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px",
color: "#111"
},
lineNum :10
}
},
init : function(container,options,width,height){
this.width = width || container.offsetWidth;
this.height = height || container.offsetHeight;
this.mainGroup = {};
//svg 里面画图 必须有一个svg标签 vml就用div了
this.container = hasSVG
? new vector().$c(1,"svg")
.attr({
xmlns : "http://www.w3.org/2000/svg",
version : "1.1"
})
.css({fontSize : "12px"})
.appendTo(container).element
: new vector().$c(1,"div")
.css({
fontSize : "12px",
width : this.width +"px",
height : this.height+"px"
})
.appendTo(container).element;
var c = extend(true,{},this.options)
var ops = this.ops = extend(true,c,options),
style = extend(ops.charts.style,{
width : this.width,
height : this.height
});
//计算绘画盘子的时候需要的一些参数
this.getDrawArea()
.createTooltip() //创建提示信息的框框
.drawTitle() //画标题
//画盘子
if("xxline,area,pie".indexOf(ops.charts.type)>=0){
ops.charts.panel = "x";
}
if(ops.charts.type!="pie"){
this.drawPanel();
}
this.drawLegend(ops.legend.type); //画色块条
var type = {
line : "drawLine",
area : "drawArea",
columns : "drawColumns",
pie : "drawPie"
}[ops.charts.type];
this[type]();
},
createElement : function(nodeName){
return new vector().$c(this,nodeName);
},
group: function(name){
return this.createElement(isIE?"div":"g").attr("mark",name);
},
getDrawArea : function(){
var ops = this.ops,
width = this.width,
height = this.height,
title = ops.title,
subTitle = ops.subTitle,
area = {
// 去掉坐标轴左边的刻度文本宽度(预估) 80为定值 左边只留80的间距
areaWidth : width - 80,
// 去掉坐标轴底下的文本和标线的高度
areaHeight : height - 40,
//原点的X位置 下面会计算到
startX : 0,
//原点的Y位置 下面会计算到
startY : 0,
//中心的x坐标 画饼图的时候需要知道圆心的位置
centerX: 0,
//中心的y坐标 画饼图的时候需要知道圆心的位置
centerY: 0
};
//如果主标题存在 减去主标题的高度 否则 减去10的高
area.areaHeight -=(title.text !== "")
? title.y
: 10;
// 去掉副标题高度
area.areaHeight -=(subTitle.text !== "")
? subTitle.y
: 10
area.startX = 80;
area.startY = height - 40;
//圆心的位置
area.centerX = width / 2;
area.centerY = height / 2;
//右边留一些空隙
area.areaWidth -=20;
//上边也留一些间距
area.areaHeight -=15;
ops.area = area;
return this;
},
drawTitle : function(){
var opts = this.ops,
self = this,
arr = [opts.title,opts.subTitle,opts.yUnit],
//3个标题坐标的位置的基本参数
config = [
{
x : this.width / 2,
y : opts.title.y
},
{
x : this.width / 2,
y : opts.subTitle.y
},
{
x : opts.yUnit.x,
y : this.height / 2 - 20
}
],
tpanel = this.group("title")
.appendTo();
each(arr,function(i,title){
var text = title.text;
if(text){
var elem = self.baseDraw("span",{
"text-anchor":"left",
x : mathMax(config[i].x - calTextLen(text,title.style).w/2,10),
y : config[i].y
},calTextLen(title.text,title.style).h)
.css(title.style)
.addText(text)
.appendTo(tpanel);
//如果为2的时候 就说明是副标题 将它竖过来
if(i===2){
hasSVG
? elem.attr({transform : "rotate(270, "+(opts.yUnit.x+10)+", " + self.height / 2 + ")"})
: (elem.element.style.filter ="progid:DXImageTransform.Microsoft.BasicImage(rotation=3)")
}
}
});
return this;
},
//画盘子 比较麻烦
drawPanel : function(type){
var opts = this.ops,
self = this,
area = opts.area,
//盘子的类型 是横盘子 还是纵盘子
type = opts.charts.panel || "x";
// 底板
var drawAreaWidth = area.areaWidth,
drawAreaHeight = area.areaHeight,
//原点的坐标
startX = area.startX,
startY = area.startY;
var allData = [],
minValue = 0,
maxValue = 10,
lineNum = mathMax(opts.yUnit.lineNum,2),
min = opts.yUnit.min,
staff;
//组合所有的数据
each(opts.chartData,function(i,o){
allData = allData.concat(o.data)
});
//给所有的数据排序 为了下面求最大值 最小值
allData.sort(function(a,b){return a-b});
//求出最大值 最小值
maxValue = allData[allData.length - 1];
each(allData,function(i,o){
if(o){
minValue = o;
return false;
}
});
//主盘子容器
this.panel = this.group("panel").appendTo();
var dd = xx(minValue,maxValue,lineNum),
min = dd.min,
max = dd.max,
f = dd.stf;
//表示画的是横坐标
if(type.toLowerCase()==="x"){
//横坐标单位间隔
var xPices = drawAreaWidth / opts.xUnit.units.length,
//单位间隔的中心点
offset = xPices / 2,
yPices = drawAreaHeight / lineNum;
//--------------------------------画横向的点和文字---------------------------------------------------------
each(opts.xUnit.units,function(i,d){
self.baseDraw("path",{
border : 1,
borderColor : "#C0C0C0",
isfill : false,
path : [
M,
processPoint(startX + (i * xPices)),
processPoint(startY),
L,
processPoint(startX + (i*xPices)),
processPoint(startY + 5)
]
}).
appendTo(self.panel);
var y = hasSVG?5:10,
span = self.baseDraw("span",{
x : startX + offset + (i * xPices),
y : startY+y,
"text-anchor":"middle"
})
.css({
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px"
})
.addText(opts.xUnit.units[i])
.appendTo(self.panel)
.element;
//vml没有x y的概念 所以要简单span宽度的一半 以后用span都需要减掉
!hasSVG
span.style.left = parseInt(span.style.left) - span.offsetWidth/2+"px";
});
//--------------------------------画纵向的点和文字-----------------------------------------------------------------------
for(i=0;i<=lineNum;i++){
self.baseDraw("path",{
border : 1,
borderColor : "#C0C0C0",
isfill : false,
path : [M, startX, processPoint(startY - (i * yPices)), L, processPoint(startX + drawAreaWidth), processPoint(startY - (i *yPices))]
})
.css({zIndex:-10})
.appendTo(self.panel);
var span = self.baseDraw("span",{
x : startX - 15,
y : startY - i * yPices-calTextLen(min+i*f+"").h/2,
"text-anchor":"middle"
})
.css({
"font-family":"Verdana,Arial,Helvetica,sans-serif",
"font-size":"12px",
width: "40px",
display:"block",
textAlign:"right"
})
.addText((min*1000+(i*1000*f/1000)*1000)/1000+"")
.appendTo(self.panel)
.element;
if(!hasSVG){
span.style.top = parseInt(span.style.top) + span.offsetHeight/2 -5+"px";
span.style.left = parseInt(span.style.left) -35+"px"
}
}
}else{
//横坐标单位间隔
var yPices = drawAreaHeight / (opts.xUnit.units.length),
//单位间隔的中心点
offset = Math.round(yPices / 2);
var x = hasSVG?25:70,
vv = hasSVG?0:5;
each(opts.xUnit.units,function(i,d){
self.baseDraw("path",{
border : 1,
borderColor : "#C0C0C0",
isfill : false,
path : [
M,
processPoint(startX-5),
processPoint(startY-i * yPices),
L,
processPoint(startX),
processPoint(startY-i * yPices),
]
})
.appendTo(self.panel);
var span = self.baseDraw("span",{
x : startX - x,
y : startY -i * yPices-offset-calTextLen(d).h/2+vv,
"text-anchor":"middle"
})
.css({
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px",
width : "60px",
textAlign:"right"
})
.addText(d)
.appendTo(self.panel)
});
var xPices = drawAreaWidth / lineNum;
for(var i=0;i<=lineNum;i++){
self.baseDraw("path",{
border : 1,
borderColor : "#C0C0C0",
isfill : false,
path : [
M,
processPoint(startX + (i * xPices)),
processPoint(startY),
L,
processPoint(startX + (i*xPices)),
processPoint(startY - drawAreaHeight)
]
}).
appendTo(self.panel);
var span = self.baseDraw("span",{
x : startX - calTextLen(min+i*f+"").w/2 + i * xPices,
y : startY,
"text-anchor":"left"
})
.css({
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px"
})
.addText(min+i*f+"")
.appendTo(self.panel)
.element;
}
}
//-----------------------------------------------------------------------------------------------------
//在画区域图的时候还需要起点的位置啊
//因为坐标很可能是负数 而且也能不是从0开始的 所以+上jianju
var jianju =0
if(min>0)jianju = min;
if(max<0)jianju = max;
//计算开始的位置
startX = opts.charts.panel==="x" ? startX :startX-xPices*(min/f);
startY = opts.charts.panel==="x" ? startY+yPices*(min/f) : startY;
opts.draw = {
startX : startX, // X 轴起点
startY : startY , // Y 轴起点
xPices : xPices, // X 轴每份的宽度
yPices : yPices, // Y 轴每份的宽度
offset : offset, // X 单分中心点位置偏移量
jianju : jianju*yPices/f,
feed : f // Y 轴的每份有多少
};
return this;
},
createTooltip : function(){
//一个组
this.tipC = this.group("tip")
.css({zIndex: 200,height:"20px",width:"20px",position:"absolute"})
.appendTo()
.hide()
//画一个框框baseDraw
this.tipBox = this.baseDraw("rect",{arc:0.22,fill:"#fff",border:2,borderColor:"#606060"})
.appendTo(this.tipC)
//因为svg里面的g可以直接定位 但是vml里面的group渲染很慢 所以改div 所以这里的父不一洋
var p = isIE ?this.tipBox :this.tipC;
this.tipTxtContainer = this.baseDraw("text",{fill:"#000000",x:5,y:19,"text-anchor":"left"})
.css({
fontFamily:"Verdana,Arial,Helvetica,sans-serif",
fontSize:"12px",
background: "#FFF"
})
.appendTo(p);
this.tipText = doc.createTextNode("");
this.tipTxtContainer[0].appendChild(this.tipText);
return this;
},
showTooltip : function(obj, x, y,data){
var txt =obj.name + ((" : " + data)||""),
size = calTextLen(txt,this.tipTxtContainer[0].style.cssText),
pos = {x : x - (size.w + 5 * 2)/2 ,y : y - 32};
this.tipC
.toFront()
.show();
if(hasSVG){
this.tipC.attr({transform:"translate("+pos.x+","+pos.y+")"});
this.tipBox
.attr({width : size.w + 5 * 2,height : size.h + 5 * 2,stroke : obj.color||"#606060"});
}else{
this.tipC.css({left:pos.x,top:pos.y});
this.tipBox
.css({width:size.w + 5 * 2,height : size.h + 5 * 2})
this.tipBox[0].strokeColor = obj.color||"#606060";
}
this.tipText.nodeValue = txt || "";
},
hideTooltip: function(){
this.tipC.hide();
},
drawLegend : function(type,redraw){
var self = this,
ops = this.ops,
//颜色块的大小
t_width = 20,
t_height = 20,
//块之间的距离
t_space = 5,
datas = ops.chartData,
len = datas.length,
css = ops.legend.style,
//最大长度 如果是纵着的 需要最大的长度
maxWidth = 10,
maxHeight = 30,
//这个东西的位置
orig_pos = ops.legend.pos?ops.legend.pos:[2,2],
//显示隐藏组的函数
handle = function(i){
var g = self.mainGroup["chart"+i];
if(g.show){
g.chart.hide();
g.show = false;
hasSVG
? this.attr({fill:"#ccc"})
: this[0].style.color = "#ccc"
}else{
g.chart.show();
g.show = true;
hasSVG
? this.attr({fill:"#000"})
: this[0].style.color = "#000"
}
},
arr = [];
type = type ||"lateral";
var legendPanel = self.group("Legend")
//.css({position:"relative"})
.appendTo();
if(type==="lateral"){
//如果是横着的
var top = orig_pos[0] + 5,
th = hasSVG?0:3,
left = orig_pos[1] + 5;
each(datas, function(i,d){
left = i===0 ? left : t_space+left;
//计算所有left的位置
self.baseDraw("rect",{
arc : 0.1,
fill : d.color,
border : 1,
borderColor : d.color,
left : left,
top : top,
width : t_width+"px",
height : t_height+"px"
})
.appendTo(legendPanel);
left = left + t_width+2 + t_space;
var w = calTextLen(d.name,css).w
self.baseDraw("span",{
"text-anchor":"left",
x : left,
y : top+th
})
.css(extend(css,{cursor:"pointer"}))
.on("click",function(){handle.call(this,i)})
.addText(d.name)
.appendTo(legendPanel);
left = left + w;
});
this.baseDraw("rect",{
arc : 0.1,
fill : "none",
border : 1.5,
borderColor : "#666666",
width : left+ t_space- orig_pos[0],
height : maxHeight,
left : orig_pos[0],
top : orig_pos[1]
})
.appendTo(legendPanel);
}else{
var top = orig_pos[0] + 5,
th = hasSVG?0:3,
left = orig_pos[1] + 5;
each(datas, function(i,d){
top = i===0 ? top : t_space + top;
self.baseDraw("rect",{
arc : 0.1,
fill : d.color,
border : 1,
borderColor : d.color,
left : left,
top : top,
width : t_width+"px",
height : t_height+"px"
})
.appendTo(legendPanel);
var h = calTextLen(d.name,css).h;
self.baseDraw("span",{
"text-anchor":"left",
x : left+t_width+2+t_space,
y : top+th
})
.css(extend(css,{cursor:"pointer"}))
.addText(d.name)
.on("click",function(){handle.call(this,i)})
.appendTo(legendPanel);
top = top + h+ t_space;
maxWidth = Math.max(maxWidth,calTextLen(d.name,css).w);
});
this.baseDraw("rect",{
arc : 0.1,
fill : "none",
border : 1.5,
borderColor : "#666666",
width : maxWidth+22+15,
height : top+t_space-orig_pos[1],
left : orig_pos[0],
top : orig_pos[1]
})
.appendTo(legendPanel);
}
return this;
},
drawLine : function(){
var self = this,
opts = this.ops,
vmlWidth = this.width,
vmlHeight = this.height
draw = opts.draw;
each(opts.chartData,function(i,o){
var id = "chart"+i,
lineGroup = self.group(id)
.appendTo();
self.mainGroup[id]={chart:lineGroup,show:true};
var path = [M],
data = o.data,
line;
for(var i = 0; i < data.length; i++){
if( data[i] == null){
//如果这个数据不存在 并且不是第一个数据 路径上加 M
if(path[path.length - 1] !== M)
path.push(M);
}else{
//如果不是第一个数据 路径添加L
i !== 0 && path.push("L");
//如果前面一个是null 并且不是第一个 把那个L去掉
if(i > 0 && data[i - 1] == null)
path.pop();
//计算出 点的x,y的位置
var x = draw.startX + draw.offset + (i * draw.xPices),
y = draw.startY - (data[i] * (draw.yPices / draw.feed));
if(isIE){
x = parseInt(x);
y = parseInt(y);
}
path.push(x);
path.push(y);
//画点
self.baseDraw("circle",{
x : x,
y : y,
r : 4,
fillColor : o.color
})
.attr({data:data[i]})
.css({zIndex:10,cursor:"pointer"})
.on("mouseover",(function(o,x,y){
return function(){
hasSVG
? (this[0].setAttribute("r","5"),line.attr({"stroke-width":2.5}))
: (this[0].strokeWeight = 3,line[0].strokeWeight = 2.5);
self.showTooltip(o,x,y,this.attr("data"));
}
})(o,x,y))
.on("mouseout",function(){
hasSVG
? (this[0].setAttribute("r","4"),line.attr({"stroke-width":1.5}))
: (this[0].strokeWeight = 1,line[0].strokeWeight = 1.5);
self.hideTooltip()
})
.on("click",function(){lineGroup.toFront(); })
.appendTo(lineGroup);
}
};
//画折线
line = self.baseDraw("path",{
border : 1.5,
borderColor : o.color,
isfill : false,
path : path
})
.css({zIndex:5})
.on("mouseover",function(){
hasSVG
? this.attr({"stroke-width":2.5})
: (this[0].strokeWeight = 2.5);
})
.on("mouseout",function(){
hasSVG
? this.attr({"stroke-width":1.5})
: (this[0].strokeWeight = 1.5);
})
.on("click",function(){lineGroup.toFront(); })
.appendTo(lineGroup);
});
return this;
},
drawArea : function(){
var self = this,
opts = this.ops,
draw = opts.draw;
each(opts.chartData,function(i,o){
var id = "chart" + i,
areaGroup = self.group(id).appendTo();
self.mainGroup[id] = {chart : areaGroup,show : true};
//有2个路径 一个是区域的路径 一个是线的路径
var areaPath = [M, (draw.startX + draw.offset).toFixed(0), (draw.startY-draw.jianju).toFixed(0)],
path = [M],
data = o.data,
line;
for(var n=0,l=data.length;n<l;n++){
//如果数据是空的
var len = areaPath.length;
if( data[n] === null){
//如果前面的一个不是m 就重新画 所以加上 M
if(path[path.length - 1] !== M)
path.push(M);
//如果第1个 或者前面的都为bull 修改起点坐标
len===3
&&(areaPath[1] = (draw.startX +(n+1)*draw.xPices + draw.offset).toFixed(0));
//如果前面一个不是结束标识符 区域图结束 如果第一个数据是null 则不进行下面的操作
if(areaPath[len - 1] !== seal&&n!==0){
areaPath=areaPath.concat([
areaPath[len - 2],
(draw.startY-draw.jianju).toFixed(0),
seal
]);
}
}else{
n !== 0 && path.push(L);
areaPath.push(L);
//如果前面的那个数据是null 把之前的那个L去掉
if(n > 0 && data[n - 1] == null){
path.pop();
//如果是第一个为null 不删除L
n!==1&&areaPath.pop();
}
var x = draw.startX + draw.offset + (n * draw.xPices),
y = draw.startY - ((data[n]) * (draw.yPices / draw.feed));
if(isIE){
x = parseInt(x);
y = parseInt(y);
}
path.push(x);
path.push(y);
if(areaPath[len - 1] === seal){
areaPath = areaPath.concat([
M,
x,
parseInt(draw.startY-draw.jianju),
L,
x,
y
]);
}else{
areaPath.push(x);
areaPath.push(y);
}
//如果是最后一个点
if(n === l - 1){
areaPath.push(x);
areaPath.push(parseInt(draw.startY-draw.jianju));
}
//画点
self.baseDraw("circle",{
x : x,
y : y,
r : 4,
fillColor : o.color
})
.attr({data:data[n]})
.on("mouseover",(function(o,x,y){
return function(){
hasSVG
? (this[0].setAttribute("r","5"),line.attr({"stroke-width":2.5}))
: (this[0].strokeWeight = 3,line[0].strokeWeight = 2.5);
self.showTooltip(o,x,y,this.attr("data"));
}
})(o,x,y))
.on("mouseout",function(){
hasSVG
? (this[0].setAttribute("r","4"),line.attr({"stroke-width":1.5}))
: (this[0].strokeWeight = 1,line[0].strokeWeight = 1.5);
self.hideTooltip()
})
.on("click",function(){areaGroup.toFront(); })
.css({zIndex:10,cursor:"pointer"})
.appendTo(areaGroup);
}
}
areaPath.push(seal)
self.baseDraw("path",{
border : 0,
isfill : true,
fillColor : o.color,
opacity : 0.5,
path : areaPath
})
.css({zIndex:5})
.appendTo(areaGroup);
line = self.baseDraw("path",{
border : 2.5,
borderColor : o.color,
isfill : false,
path : path
})
.on("mouseover",function(){
hasSVG
? this.attr({"stroke-width":2.5})
: (this[0].strokeWeight = 2.5);
})
.on("mouseout",function(){
hasSVG
? this.attr({"stroke-width":1.5})
: (this[0].strokeWeight = 1.5);
})
.on("click",function(){areaGroup.toFront(); })
.css({zIndex:-1})
.appendTo(areaGroup);
});
return this;
},
drawColumns : function(){
var self = this,
opts = this.ops,
draw = opts.draw,
chartData = opts.chartData,
dataLen = chartData.length,
//多个柱子之间的间距
columnSpace = 3,
//一个位置中 所有的间隔之和
columnPadding = columnSpace * dataLen + columnSpace,
//每个柱子的宽度
columnSize = self.ops.charts.panel==="x"
? Number(((draw.xPices - columnPadding) / dataLen).toFixed(0))
: Number(((draw.yPices - columnPadding) / dataLen).toFixed(0));
each(chartData, function(i,o){
var data = o.data,
id = "chart" + i,
isX = opts.charts.panel==="x",
colGroup = self.group(id).appendTo(),
//每个点开始的位置
start = self.ops.charts.panel==="x"
? draw.startX + columnSpace + i*(columnSize+columnSpace)
: draw.startY + columnSpace + i*(columnSize+columnSpace)
self.mainGroup[id] = {chart:colGroup,show:true};
for(var j = 0,l=data.length; j < l ; j++){
if(data[j]===null) continue;
//如果是横盘子
if(isX){
var x = Number((start + j *draw.xPices ).toFixed(0)),
y = Number((draw.startY).toFixed(0)),
height = Number((data[j] * (draw.yPices / draw.feed)).toFixed(0)),
path = [
M,
x,
y,
L,
x,
y -height,
L,
x + columnSize,
y - height,
L,
x + columnSize,
y,
seal
];
var pos = [x+columnSize/2,data[j]>0?y-height:draw.startY];
}else{
var x = Number((draw.startX).toFixed(0)),
width = Number((data[j]*((draw.xPices / draw.feed))).toFixed(0)),
y = Number((start - (j+1) *draw.yPices ).toFixed(0)),
path = [
M,
x,
y,
L,
x+ width,
y ,
L,
x + width,
y + columnSize,
L,
x ,
y+ columnSize,
seal
];
var pos = [draw.startX+width/2,y-columnSize];
}
self.baseDraw("path",{
border : 0,
isfill : true,
fillColor : o.color,
opacity : 1,
path : path
})
.attr({data:data[j]})
.css({zIndex:5,cursor:"pointer"})
.on("mouseover",(function(x,y,d){
return function(){
this.setOpacity(0.85);
self.showTooltip(o,x,y,this.attr("data"));
}
})(pos[0],pos[1],data[j])
)
.on("mouseout",(function(x,y){
return function(){
this.setOpacity(1);
self.hideTooltip();
}
})(x,y))
.appendTo(colGroup);
}
});
return this;
},
drawPie : function(){
var self = this,
opts = this.ops,
area = opts.area,
rx = area.centerX,
ry = area.centerY,
inc = 0,
total = 0,
data = [],
cumulative = -0.25, // start at top;
circ = 2 * Math.PI,
radiu = mathMin(opts.charts.radius,mathMin(area.areaWidth/2,area.areaHeight/2)),
fraction,
half_fraction;
each(opts.chartData,function(i,o){
typeof o ==="object"
? (data.push((function(o){
var all =0;
for(var i in o)
all+=~~o[i]
return all
})(o.data)))
:data.push(~~o.data)
});
each(data,function(i,o){
total = total + o;
});
each(data,function(i,o){
var pieGroup = self.group("chart"+i).appendTo(),
s = inc/total*360,
e =(inc + o)/total*360,
pie;
inc = inc + o;
//----------------------生成文字开始----------------------------------------------------------
var name = opts.chartData[i].name,
size = calTextLen(name)
dot = angle(radiu,[rx,ry],s+(e-s)/2,2),
x = rx + (dot[0]-rx)/2 - size.w/2,
y = ry + (dot[1]-ry)/2 - size.h/2,
len = Math.sqrt((x-rx)*(x-rx)+(y-ry)*(y-ry)),
moveDisplacement = ((x-rx)*8/len)+","+((y-ry)*8/len);
//-------------------------生成文字结束-------------------------------------------------------
if(hasSVG){
var value = Number(o);
fraction = total ? value / total : 0;
half_fraction = total ? (value / 2) / total : 0;
var start = cumulative * circ;
half_cumulative = cumulative + half_fraction;
cumulative += fraction;
var end = cumulative * circ;
var half_end = half_cumulative * circ;
pie = self.baseDraw("pie",{
config : opts.chartData[i],
s : start,
e : end,
r : radiu,
index : i
})
}else{
pie=self.baseDraw("pie",{
config : opts.chartData[i],
s : s,
e : e,
r : radiu,
index : i
})
}
pie.css({zIndex:5,cursor:"pointer"})
.attr({move:moveDisplacement})
.on("mouseover",function(){
this.setOpacity(0.85);
})
.on("mouseout",function(){
this.setOpacity(1);
})
.on("click",function(){
var m = this.attr("move")
if(m.indexOf("+")>0){
hasSVG
? this.attr({
transform: "translate(0,0)"
})
: this.css({
left : "0px",
top : "0px"
})
this.attr({move:m.replace("+","")});
}else{
var s= m.split(",");
hasSVG
? this.attr({
transform: "translate("+m+")"
})
:this.css({
left : s[0]+"px",
top : s[1]+"px"
})
this.attr({move:m+"+"});
}
})
.appendTo(pieGroup);
self.mainGroup["chart"+i] = {chart:pieGroup,show:true};
self.baseDraw("span",{
x : x,
y : y,
fill : "#fff",
"text-anchor":"left"
})
.css({
fontFamily : "Verdana,Arial,Helvetica,sans-serif",
fontSize : "12px",
position : "absolute",
color : "#fff",
zIndex : 10
})
.addText(name)
.appendTo(pieGroup);
});
},
baseDraw : function(type,config){
var self = this
arg = arguments;
return {
rect : function(){
var set = {};
set.rx = set.ry = config.arc*30 || 5;
set.width = config.width || 50;
set.height = config.height || 50;
set.fill = config.fill || "#fff";
set["fill-opacity"] = config.opacity || 0.85;
set["stroke-width"] = config.border || 2;
set.stroke = config.borderColor || "#606060";
set.transform = "translate("+(config.left||0)+","+(config.top||0)+")";
return self.createElement("rect")
.attr(set)
},
text : function(){
return self.createElement("text")
.attr(config)
},
span : function(){
var elem= self.createElement("text")
.attr(config)
.attr({
y : config.y+(arg[2]||15)
})
return elem
},
path : function(){
var set = {};
set["stroke-width"] = config.border;
set.stroke = config.borderColor || "#C0C0C0";
set.fill = config.isfill?config.fillColor:"none";
set.d = config.path;
config.opacity
&&(set["fill-opacity"] = config.opacity);
return self.createElement("path")
.attr(set);
},
circle : function(){
var set = {};
set.cx = config.x;
set.cy = config.y;
set.r = config.r;
set.fill = config.fillColor;
return self.createElement("circle")
.attr(set);
},
pie : function(){
//config,s,e,r,index
var opts = self.ops,
s = config.s,
r = config.r,
e = config.e - 0.000001,
id = "chart"+config.index,
area = opts.area,
rx = area.centerX,
ry = area.centerY,
cosStart = mathCos(s),
sinStart = mathSin(s),
cosEnd = mathCos(e),
sinEnd = mathSin(e),
color = config.config.color,
name = config.config.name,
longArc = e - s < Math.PI ? 0 : 1,
path = [
M,
rx + r * cosStart,
ry + r * sinStart,
"A",
r,
r,
0,
longArc,
1,
rx + r * cosEnd,
ry + r * sinEnd,
L,
rx + 0 * cosEnd,
ry + 0 * sinEnd,
"A", // arcTo
0, // x radius
0, // y radius
0, // slanting
longArc, // long or short arc
0, // clockwise
rx + 0 * cosStart,
ry + 0 * sinStart,
"Z"
];
return self.baseDraw("path",{
border : 1,
border : "#fff",
isfill : true,
fillColor : color,
opacity : 1,
path : path
})
}
}[type]();
}
};
//---------------------------------------------------------------------------------------------------
//如果是vml 修改smipleChart.prototype中的一些方法
!hasSVG
&&extend(smipleChart.prototype,{
baseDraw : function(type,config){
var self = this,
width = this.width,
height = this.height,
name = arguments[2];
return {
rect : function(){
var attr = {},
css = {};
attr.arcsize = config.arc || 0.2 +"";
if(config.fill==="none"){
attr.filled = "f"
}else{
attr.filled = "t";
attr.fillcolor = config.fill || "#fff";
}
attr.strokeWeight = config.border || 2;
attr.strokeColor = config.borderColor || "#606060";
css.width = config.width || 50 +"px";
css.height = config.height || 50 +"px";
css.zIndex = 10;
css.left = config.left||0+"px";
css.top = config.top ||0+"px";
return self.createElement("roundrect")
.attr(attr)
.css(css)
},
text : function(){
return self.createElement("TextBox")
.attr({inset : "2px,2px,2px,2px" })
},
span : function(){
return self.createElement("span").
css({
position:"absolute",
left : config.x+"px",
top : config.y+"px"
})
},
path : function(){
var attr = {},
css = {
width : width+"px",
height : height+"px"
};
if(config.border===0){
attr.Stroked = "f";
attr.strokeWeight =0;
}else{
attr.strokeWeight = config.border||1 ;
}
attr.strokeColor = config.borderColor || "#C0C0C0";
attr.filled = config.isfill?"t":"f";
attr.filled==="t"
&&(attr.fillcolor=config.fillColor||"#C0C0C0");
attr.coordsize = width+","+height;
attr.path = config.path;
var elem = self.createElement()
.attr(attr)
.css(css);
if(config.opacity){
var fill = self.createElement("fill")
.attr({
type : "fill",
color : config.fillColor||"#C0C0C0",
opacity : config.opacity
})
.appendTo(elem);
//那这个对象的一个属性引用设置透明的元素 以后会用到
elem.opacity = fill[0];
}
return elem;
},
circle : function(){
var attr ={
strokeWeight : 1,
coordsize : width+","+height,
filled : "t"
},
css ={
width : width+"px",
height : height+"px"
}
x = config.x,
y = config.y,
r = config.r;
attr.strokeColor=attr.fillcolor = config.fillColor
attr.path =[
"wa", // clockwisearcto
x - r, // left
y - r, // top
x + r, // right
y + r, // bottom
x + r, // start x
y, // start y
x + r, // end x
y, // end y
"e" // close
];
return self.createElement()
.attr(attr)
.css(css)
},
pie : function(){
////config,s,e,r,index
var opts = self.ops,
area = opts.area,
r = config.r,
s = config.s,
e = config.e,
rx = area.centerX,
ry = area.centerY,
sDot = angle(r,[rx,ry],s,2),
eDot = angle(r,[rx,ry],e,2),
color = config.config.color,
name = config.config.name,
path = [
"M 0 0 ar",
rx-r,
ry-r,
rx+r,
ry+r,
~~eDot[0],
~~eDot[1],
~~sDot[0],
~~sDot[1],
"l",
rx,
ry,
"x"
];
return self.baseDraw("path",{
border : 1,
border : "#fff",
isfill : true,
fillColor : color,
opacity : 1,
path : path
})
}
}[type]();
}
});
//---------------------------------------------------------------------------------------------------
})(document);
window.onload = function(){
var config = {
charts : {
type : "line",
radius : 150,
panel : "x",
style: {
fontFamily: ""Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif", // default font
fontSize: "12px"
}
},
title : {
text : "线性图标" ,
y : 10,
style : {
color: "black",
fontSize: "16px"
}
},
subTitle : {
text : "线性图标副标题",
y : 35,
style: {
color: "#111",
fontSize: "12px"
}
},
legend : {
enable : true,
//type : "lateral", // lateral 横向 或 lengthwise 纵向
type : "lateral",
pos : [10,10],
style:{
fontFamily: ""Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, Helvetica, sans-serif", // default font
fontSize: "12px",
magin:"0px"
}
},
yUnit : {
text : "线性图标侧标题",
x : 20,
style: {
color : "#111",
fontSize : "12px"
}
},
xUnit : {
units: [
"一月",
"二月",
"三月",
"四月",
"五月",
"六月",
"七月",
"八月",
"九月",
"十月",
"十一月",
"十二月"
]
},
chartData : [
{
name : "xcv",
color : "#4572A7",
data : [-18,45,-38,29,95,-45,77]
}, {
name: "frfr",
color: "#AA4643",
data: [-44,12,78,-100,13,4,-56,-34]
}, {
name: "AAAAA",
color: "#89A54E",
data: [null,78,83,null,22,-78,2,44,78]
}, {
name: "BBBB",
color: "#80699B",
data: [null, 58, 35, null, 52, 47, 26, -55, 39, 123,15,66]
}
]
};
new smipleChart($("line"),config);
config.charts.type ="area";
config.title.text ="区域图标"
config.subTitle.text="区域图标副标题"
config.yUnit.text ="区域图标侧标题"
new smipleChart($("area"),config);
config.title.text ="柱状图标"
config.subTitle.text="柱状图标副标题"
config.yUnit.text ="柱状图标侧标题"
config.charts.type ="columns";
config.chartData =[
{
name : "xcv",
color : "#4572A7",
data : [-0.01,-0.62,0,0.55,null,0.78,-0.63,-0.82,null,null,0.33]
}, {
name: "frfr",
color: "#AA4643",
data: [-0.22,0.82,0.55,1.32,0.33,0.95,null,1,0.65,null,0.78]
}, {
name: "AAAAA",
color: "#89A54E",
data: [null,0.62,0.34,null,0.63,0,-0.23,-1,0.62,0.45,null,-0.56]
}
]
new smipleChart($("zhu"),config);
config.charts.panel="y"
new smipleChart($("zhu1"),config);
config.charts.type ="pie";
config.title.text ="饼图图标"
config.subTitle.text="饼图图标副标题"
config.yUnit.text =""
config.legend.type="lengthwise";
config.chartData =[
{
name : "xcv",
color : "#4572A7",
data : [433,355,275,null,588,323,576,32,99]
}, {
name: "frfr",
color: "#AA4643",
data: [45,666,100,null,677,56,88,633,55,64]
}, {
name: "AAAAA",
color: "#89A54E",
data: [55,162,75,null,364,0,637,112,163,615]
}
]
new smipleChart($("pie"),config);
config.yUnit.lineNum = 2;
config.title.text ="比较小的"
config.subTitle.text="只设置了2条线"
config.yUnit.text ="小测标题" ;
config.charts.type ="line";
config.legend.type="lateral";
new smipleChart($("vv"),config);
}
</script>
</body>
</html>