javascript smipleChart 简单图标类 |
因为编辑器会对代码有所破坏,所以提供一个在线演示 复制代码 代码如下: <!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=pies class="cc"></div> <div id=segment 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 opts = this.opts = extend(true,c,options), style = extend(opts.charts.style,{ width : this.width, height : this.height }); //计算绘画盘子的时候需要的一些参数 this.getDrawArea() .createTooltip() //创建提示信息的框框 .drawTitle() //画标题 //画盘子 if(line,area,pie.indexOf(opts.charts.type)>=0){ opts.charts.panel = x; } if( pie,pies.indexOf(opts.charts.type)<0){ this.drawPanel(); } this.drawLegend(opts.legend.type); //画色块条 var type = { line : drawLine, area : drawArea, columns : drawColumns, pie : drawPie, pies : drawPies, segment : drawSegment }[opts.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 opts = this.opts, width = this.width, height = this.height, title = opts.title, subTitle = opts.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; opts.area = area; return this; }, drawTitle : function(){ var opts = this.opts, 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.opts, self = this, area = opts.area, isSegment= opts.charts.type===segment, //盘子的类型 是横盘子 还是纵盘子 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){ isSegment ? each(o.data,function(j,d){ allData[j] ? allData[j] = allData[j] + (''d) : allData[j] = ''d; }) : 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, opts = this.opts, //颜色块的大小 t_width = 20, t_height = 20, //块之间的距离 t_space = 5, datas = opts.chartData, len = datas.length, css = opts.legend.style, //最大长度 如果是纵着的 需要最大的长度 maxWidth = 10, maxHeight = 30, //这个东西的位置 orig_pos = opts.legend.pos?opts.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) .appendTo(); if(type===lateral){ //如果是横着的 var top = orig_pos[1] + 5, th = hasSVG?0:3, left = orig_pos[0] + 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(){ if(opts.charts.type===pies)return; 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[1] + 5, th = hasSVG?0:3, left = orig_pos[0] + 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(){ if(opts.charts.type===pies)return; 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.opts; 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.opts, 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.opts, draw = opts.draw, chartData = opts.chartData, dataLen = chartData.length, //多个柱子之间的间距 columnSpace = 3, //一个位置中 所有的间隔之和 columnPadding = columnSpace * dataLen + columnSpace, //每个柱子的宽度 columnSize = self.opts.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.opts.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.opts, 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.data ===object ? (data.push((function(o){ var all =0; for(var i in o) all+=''o[i] return all })(o.data))) :data.push(mathAbs(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, 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); inc = inc + o; 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; self.baseDraw(pie,{ config : opts.chartData[i], s : start, e : end, r : radiu, innerR : 0 }) .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); }); }, drawPies : function(){ var self = this, opts = this.opts, area = opts.area, rx = area.centerX, ry = area.centerY, total = 0, data = [], chartData = opts.chartData, cumulative = -0.25, // start at top; circ = 2 * Math.PI, radiu = mathMin(opts.charts.radius,mathMin(area.areaWidth/2,area.areaHeight/2)), fraction, half_cumulative, half_fraction; each(chartData,function(i,o){ each(o.data,function(j,d){ data[j] ? data[j] +=mathAbs(d) : data[j] =mathAbs(d) }); }); //看有多少个数据来生成来生成内半径 var len = data.length, innerSpace = radiu / 10; Rpice = (radiu - innerSpace) / len, piesGroup = this.group(pies).appendTo(); each(data,function(i,d){ var inc = 0 ; if(d===0) return; each(chartData,function(j,o){ if(''o.data[i]===0)return; var outR = radiu - Rpice * i, innerR = radiu - Rpice * (i + 1), value = ''o.data[i], fraction = value / d; half_fraction = (value/2)/d , start = cumulative * circ, s = inc/d*360, e = (inc + value)/d*360; inc = inc + value; var name = o.name, size = calTextLen(name), dot = angle(radiu,[rx,ry],s+(e-s)/2,2), px = dot[0]>rx?1:-1, py = dot[1]>ry?1:-1; var x = rx + px*innerSpace + ((dot[0]-rx-px*innerSpace)/len)*(len-i-1)+((dot[0]-rx-px*innerSpace)/len)/2- size.w/2, y = ry + py*innerSpace +((dot[1]-ry-py*innerSpace)/len)*(len-i-1)+((dot[1]-ry-py*innerSpace)/len)/2- size.h/2; half_cumulative = cumulative + half_fraction, cumulative += fraction, end = cumulative * circ; self.baseDraw(pie,{ config : o, s : start, e : end, r : outR, innerR : innerR }) .css({zIndex:5,cursor:pointer}) .on(mouseover,function(){ this.setOpacity(0.85); }) .on(mouseout,function(){ this.setOpacity(1); }) .appendTo(piesGroup); 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(piesGroup); }) }); }, drawSegment : function(){ var self = this, opts = this.opts, draw = opts.draw, chartData = opts.chartData, columnPad = 5, columnWidth = draw.xPices - columnPad * 2; each(chartData,function(i,c){ }); }, 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.opts, 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, innerR = config.innerR, 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 + innerR * cosEnd, ry + innerR * sinEnd, A, // arcTo innerR, // x radius innerR, // y radius 0, // slanting longArc, // long or short arc 0, // clockwise rx + innerR * cosStart, ry + innerR * 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.opts, area = opts.area, r = config.r, rx = area.centerX, ry = area.centerY, innerR= config.innerR||0, sDot = angle(r,[rx,ry],s,2), eDot = angle(r,[rx,ry],e,2), color = config.config.color, s = config.s, e = config.e, e = e - s == 2 * Math.PI ? e - 0.001 : e, cosStart = mathCos(s), sinStart = mathSin(s), cosEnd = mathCos(e), sinEnd = mathSin(e), path = [ wa, // clockwisearcto (rx - r).toFixed(0), // left (ry - r).toFixed(0), // top (rx + r).toFixed(0), // right (ry + r).toFixed(0), // bottom (rx + r * cosStart).toFixed(0), // start x (ry + r * sinStart).toFixed(0), // start y (rx + r * cosEnd).toFixed(0), // end x (ry + r * sinEnd).toFixed(0), // end y at, // clockwisearcto (rx - innerR).toFixed(0), // left (ry - innerR).toFixed(0), // top (rx + innerR).toFixed(0), // right (ry + innerR).toFixed(0), // bottom (rx + innerR * cosEnd).toFixed(0), // start x (ry + innerR * sinEnd).toFixed(0), // start y (rx + innerR * cosStart).toFixed(0), // end x (ry + innerR * sinStart).toFixed(0), // end y x, // finish path e // close ]; 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 : aaa, color : #4572A7, data : [433,123,null,66] }, { name: bbb, color: #AA4643, data: [45,33,33,511] }, { name: ccc, color: #89A54E, data: [55,null,75,333] } ] config.legend.pos= [680,30] new smipleChart($(pie),config); config.charts.type =pies; config.title.text =多层饼图图标 config.subTitle.text=多层饼图图标副标题 config.legend.type=lateral; config.legend.pos= [330,400] new smipleChart($(pies),config); 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] } ] config.yUnit.lineNum = 2; config.title.text =比较小的 config.subTitle.text=只设置了2条线 config.yUnit.text =小测标题 ; config.charts.type =line; config.legend.pos= [10,10] new smipleChart($(vv),config); config.yUnit.lineNum = 10; config.charts.panel = x; config.charts.type =segment; //new smipleChart($(segment),config); } </script> </body> </html> |