javascript使用smipleChart实现简单图表


Posted in Javascript onJanuary 02, 2015

支持 线性图 区域图 柱状图 饼图

支持多浏览器

用到的是svg  vml

<!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='segmentx' class="cc"></div>

<div id='segmenty' class="cc"></div>

<div id='pie' class="cc"></div>

<div id='pies' class="cc"></div>

<div id='vv' class="cc" style='height:300px; width:520px;'></div>

<script type="text/javascript">

(function(doc,undefined){

 var win       = this,

  uuuid     = -1, 

  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;  

 }; 

 

 win.contains = function(p,c){

  if(!p||!c)return false;

  if(p===c)return true;

  return isIE

   ? p.contains(c)

   : p.compareDocumentPosition(c)==20

    ? true

    : false;

 };

//---------------------------------------------------------------

 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   = 1000,

   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;

   }

  }); 

  var bj  = (mathAbs(a)*t)/(v*t),

   ba  = 0,

   isZ = bj!==parseInt(bj);

  isZ

   &&a>0

    ? ba = -a%v*t

    : ba = (mathAbs(a)%v-v)*t;  

  

  

  a = (a*t+ba)/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){

  

  //坐标比较整数化 

   if(a!=0&&num!=0&&a%10!==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{

   //坐标比较整数化 

   if(b<0&&num!=0){

    while(b!=0&&num!=0&&b%10!==0){

     b = (b*t+v*t)/t;

     num--;

     if((b*t+v*num*t)/t<0&&b%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(){};

 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){

   for(var key in hash){

    isIE && key == "opacity"

     ? this[0].style['filter'] = "alpha(opacity="+ hash[key] * 100+")"

     : this[0].style[key] = hash[key];

   }

   return this;

  },

  on: function(eventName, handler){

   var self = this;

   /*this.element.addEventListener(eventName,function(){

    handler.call(self)

   },false);*/

   this.element['on' + eventName] = function(e){

    e = e || win.event;

    handler.call(self,e);

   }   

   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+''));

   }

   return this;

  },

  setOpacity : function(v){

   this.attr('fill-opacity',v);

   return this;

  },

  setSize : function(v){

   this[0].nodeName==='circle'

    ? this.attr('r',4+(v===0?0:2))

    : this.attr({'stroke-width':v});

   return this;

  },

  toFront: function() {

   this[0].parentNode.appendChild(this[0]);

   return this;

  },  

  show: function(){

   this[0].style.display = 'block';

   return this;

  },

  hide: function(){

   this[0].style.display = 'none';

   return this;    

  },

  destroy : function(){

   //销毁节点......................

   var node = this[0] || this;

   node.onmouseover = node.onmouseout = node.onclick = null;

   node.parentNode

    &&node.parentNode.removeChild(node);

   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){

    this[0].innerHTML = txt || '';

    return this;

   },

   setSize : function(v){

    this[0].strokeWeight = v;

    return this;

   },   

   setOpacity : function(v){

    this.opacity.opacity=v;

    return this;

   }  

  });

 }

//---------------------------------------------------------------------------------------------------

//画图类 

//------------------------------------------------------------

 win.smipleChart = function(){

  this.init.apply(this,arguments);

 };

 smipleChart.list      = [];

 smipleChart.timer     = null;

 smipleChart.lazyLoad  = function(id){

  id  = id || '0' 

  smipleChart.list[id]

   &&smipleChart.list[id].loadMe();

 };

 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){

   clearTimeout(smipleChart.timer)

   var self      = this;

   this.width    = container.offsetWidth;

   this.height   = container.offsetHeight;

   this.currList = {};

   this.uuuid    = ++uuuid; 

   this.timer    = null;

   //主要画图组的集合 形式

   //{id : {dom:xx,show:true}}

   this.mainGroup = {};

   //分段的时候要用到的  知道哪些是隐藏了的  因为要涉及到重绘

   this.hideList  = {};

   

   //svg 里面画图 必须有一个svg标签 vml就用div了

   this.container = hasSVG 

    ? new vector().$c(1,'svg')

     .attr({

      xmlns   : 'http://www.w3.org/2000/svg',

      version : '1.1',

      width : this.width,

      height : this.height

      

     })

     .css({fontSize : '12px'})

     .appendTo(container)

    : new vector().$c(1,'div')

     .css({

      fontSize : '12px',

      width    : this.width +'px',

      height   : this.height+'px'

     })

     .appendTo(container);

     

   this.loading = container.appendChild(doc.createElement('img'));

   this.loading.setAttribute('src','http://images.cnblogs.com/cnblogs_com/wtcsy/192373/r_loading.gif');

   this.loading.style.position = 'absolute';

   this.loading.style.top  = container.offsetHeight/2- this.loading.offsetHeight/2+'px';

   this.loading.style.left = container.offsetWidth/2- this.loading.offsetWidth/2+'px';

  

   var c     = extend(true,{},this.options),

    opts  = this.opts = extend(true,c,options),

    style = extend(opts.charts.style,{

     width  : this.width,

     height : this.height

    });

   

   smipleChart.list[this.uuuid] = this; 

   

   smipleChart.timer = setTimeout(function(){

    smipleChart.lazyLoad();

   },200);

      

  },

  loadMe : function(){

   var opts  = this.opts,

    self  = this,

    type  = opts.charts.type;

   this.container = this.container

    .on('mouseout',function(e){

     var elem = e.relatedTarget || e.toElement;

     if(!contains(this[0],elem)){

      self.hideTooltip();

      self.currList.dot

       &&self.currList.dot.setSize(0);

      self.currList.line

       &&self.currList.line.setSize(1.5);

      self.currList = {}; 

     }

    })

    .css({display:'none'})[0];

    

        

   //计算绘画盘子的时候需要的一些参数

   this.getDrawArea()

    .createTooltip()         //创建提示信息的框框

    .drawTitle()             //画标题

                //画盘子

    

   'line,area,pie'.indexOf(type)>=0

    &&(opts.charts.panel = 'x');

   

   

   ' pie,pies'.indexOf(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]();

   

   //删除节点

   this.loading.parentNode.removeChild(this.loading);

   //断开引用

   this.loading = null;

   

   this.container.style.display = '';

   setTimeout(function(){

    smipleChart.lazyLoad((++self.uuuid)+'');

   },10)

   

  },

  createElement : function(nodeName){

   return new vector().$c(this,nodeName);

  },

  group: function(name){

   return this.createElement(hasSVG?'g':'div').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(self,{

       '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,

    chartsType = opts.charts.type,

    isSegment  = chartsType === '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,

    //线的条数 只能在1到10之间

    lineNum  = mathMin(10,mathMax(opts.yUnit.lineNum,1)),

    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!==null){

     minValue = o;

     return false;

    }    

   });    

       

   //主盘子容器

   var panel = this.group('panel').appendTo();

  

   var result = xx(minValue,maxValue,lineNum),

    min    = result.min,

    max    = result.max,

    f      = result.stf;

   isSegment

    &&(min = 0);   

   //表示画的是横坐标 或者是双坐标

   if(type.toLowerCase()==='x'){

    //横坐标单位间隔

    var xPices = drawAreaWidth / opts.xUnit.units.length,

     //单位间隔的中心点

     offset = xPices / 2,

     

     yPices = drawAreaHeight / lineNum;

   

 //--------------------------------画横向的点和文字---------------------------------------------------------

    var y = hasSVG?5:10,

     t = 1000,

     span;   

    each(opts.xUnit.units,function(i,d){        

     self.baseDraw.path(self,{

      border      : 1,

      borderColor : '#C0C0C0',

      isfill      : false,

      path        : [

       M, 

       processPoint(startX + (i * xPices)), 

       processPoint(startY), 

       L,

       processPoint(startX + (i*xPices)),

       processPoint(startY + 5)

      ]

     }).

     appendTo(panel);

    

     span = self.baseDraw.span(self,{

       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(panel)[0];

     

     !hasSVG

      &&(span.style.left = parseInt(span.style.left) - span.offsetWidth/2+'px');

      

    });

//--------------------------------画纵向的点和文字-----------------------------------------------------------------------    

    for(i=0;i<=lineNum;i++){

     self.baseDraw.path(self,{

      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(panel);

     

     var span = self.baseDraw.span(self,{

      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*t+(i*t*f/t)*t)/t+'')

     .appendTo(panel)[0];

     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),

     x      = hasSVG ? 25 : 70,

     y     = hasSVG ? 0 : 5,

     span

    

    each(opts.xUnit.units,function(i,d){           

     self.baseDraw.path(self,{

      border      : 1,

      borderColor : '#C0C0C0',

      isfill      : false,

      path        : [

       M,

       processPoint(startX-5),

       processPoint(startY-i * yPices),

       L,

       processPoint(startX),

       processPoint(startY-i * yPices),

      ]

     })

     .appendTo(panel);

     span = self.baseDraw.span(self,{

      x   : startX - x,

      y   : startY -i * yPices-offset-calTextLen(d).h/2 + y,

      'text-anchor':'middle'

     })

     .css({

       fontFamily:'Verdana,Arial,Helvetica,sans-serif',

       fontSize:'12px',

       width   : '60px',

       textAlign:'right'

     })

     .addText(d)

     .appendTo(panel)   

  

    });

    

    

    var xPices = drawAreaWidth / lineNum;

    

    for(var i=0;i<=lineNum;i++){

     self.baseDraw.path(self,{

      border      : 1,

      borderColor : '#C0C0C0',

      isfill      : false,

      path        : [

       M, 

       processPoint(startX + (i * xPices)), 

       processPoint(startY), 

       L, 

       processPoint(startX + (i*xPices)),

       processPoint(startY - drawAreaHeight)

      ]

     }).

     appendTo(panel);

     

     self.baseDraw.span(self,{

      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(panel);   

    }

    

   }

//----------------------------------------------------------------------------------------------------- 

   //因为起点很可能不是从0开始的  所以在起点的时候要要加上到0那部分的值

   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 单分中心点位置偏移量

     jianjuY : jianju*yPices/f,

     jianjuX : jianju*xPices/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(this,{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(this,{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||'#000';    

   }

   this.tipText.nodeValue = txt || '';*/

   clearTimeout(this.timer);

   var txt  = obj.name +':' + data,

    self = this,

    size = calTextLen(txt,this.tipTxtContainer[0].style.cssText),

    pos  = {x : x - (size.w + 5 * 2)/2 ,y : y - 32};

   if(hasSVG){          

    self.tipBox

     .attr({width  : size.w + 5 * 2,height : size.h + 5 * 2,stroke : obj.color||'#606060'});

   }else{          

    self.tipBox

     .css({width:size.w + 5 * 2,height : size.h + 5 * 2})

    self.tipBox[0].strokeColor = obj.color||'#000';    

   }

   this.tipText.nodeValue = txt || '';

   

   if(this.tipC[0].style.display === 'none'){

    hasSVG

     ? self.tipC.attr({transform:'translate('+pos.x+','+pos.y+')',pos:pos.x+'-'+pos.y})

     : self.tipC.attr({pos:pos.x+'-'+pos.y}).css({left:pos.x,top:pos.y});

    this.tipC

     .toFront()

     .show();

        

   }else{

    var move = function(t,b,c,d){

               return c*(t/=d)*t + b;

           },

     t = 0,

     b = self.tipC.attr('pos').split('-'),

     c = [pos.x,pos.y],

     d = 5;

    

    this.timer = setInterval(function(){

     if(t<d){

      t++;

      

     var x = move(t,~~b[0],(~~c[0])-(~~b[0]),d),

      y = move(t,~~b[1],(~~c[1])-(~~b[1]),d);

     hasSVG

      ? self.tipC.attr({transform:'translate('+x+','+y+')',pos:x+'-'+y})

      : self.tipC.attr({pos:x+'-'+y}).css({left:x,top:y});

     }else{

      clearTimeout(self.timer);

     }

    },1);

   }; 

  },

  hideTooltip: function(){

   this.tipC.hide();

  },   

  drawLegend : function(type,redraw){

   var self   = this,

    opts   = this.opts,

    isLine = opts.charts.type === 'line', 

    //颜色块的大小

    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],

      issegment = opts.charts.type==='segment';

     

     if(g.show){

      g.chart.hide();

      g.show = false;

      hasSVG

       ? this.attr({fill:'#ccc'})

       : this[0].style.color = '#ccc';

      

      

      //如果是分段图  是会涉及到重画的

      if(issegment){

       self.hideList[i] ='';

       var mainGroup = self.mainGroup;

     

       for(var name in mainGroup){ 

        var parent = mainGroup[name].chart,

         nodes  = parent[0].childNodes,

         len    = nodes.length;

        //销毁图上面画的东西

        for(var i = len-1;i>=0;i--){

         vector.prototype.destroy.call(nodes[i])

        }  

       }

       //重画 

       self.drawSegment();

      } 

 

     }else{

      g.chart.show();

      g.show = true;

      hasSVG

       ? this.attr({fill:'#000'})

       : this[0].style.color = '#000'

       

      if(issegment){

       delete self.hideList[i];

       var mainGroup = self.mainGroup;

     

       for(var name in mainGroup){

        

        var parent = mainGroup[name].chart,

         nodes  = parent[0].childNodes,

         len    = nodes.length;

        for(var i = len-1;i>=0;i--){

         vector.prototype.destroy.call(nodes[i])

        } 

 

       }

       self.drawSegment();

      }        

     }

    },

    

    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的位置

     //如果是线性图  按线性图的方式画图

     if(isLine){

      self.baseDraw.path(self,{

       border      : 1.5,

       borderColor : d.color,

       isfill      : false,

       path        : [

        M,

        left.toFixed(0),

        (top+10).toFixed(0),

        L,

        (left+25).toFixed(0),

        (top+10).toFixed(0)

       ]

        })

        .appendTo(legendPanel);

      self.baseDraw[d.dotType || 'circle'](self,{

       x : left+12,     

       y : top+10,

       r : 4,

       fillColor : d.color

      })

      .appendTo(legendPanel);

     }else{

      self.baseDraw.rect(self,{

       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(self,{

      '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(this,{

      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(self,{

      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(self,{

      '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(this,{

      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,l = data.length; i < l ; 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);

      //画点

      var dotType = o.dotType||'circle';

      self.baseDraw[dotType](self,{

       x : x,     

       y : y,

       r : 4,

       fillColor : o.color

      })

      .attr({data:data[i],pos:x+'-'+(y-5)})

      .css({zIndex:10,cursor:'pointer'})

      .on('mouseover',(function(o,x,y){

       return function(){

        if(self.currList.dot){

         if(self.currList.dot[0] === this[0])

          return;

         self.currList.dot.setSize(0);

         self.currList.line.setSize(1.5);

        }

        this.setSize(2);

        line.setSize(2.5);

        var pos = this.attr('pos').split('-');

        self.showTooltip(o,pos[0],pos[1],this.attr('data'));

        self.currList.dot  = this;

        self.currList.line = line;

       }                  

      })(o,x,y))

      /*.on('mouseout',function(){    

       this.setSize(0);

       line.setSize(1.5);

      })*/

      .on('click',function(){lineGroup.toFront(); })

      .appendTo(lineGroup);

     }

    };

    //画折线

    line = self.baseDraw.path(self,{

     border      : 1.5,

     borderColor : o.color,

     isfill      : false,

     path        : path

    })

    .css({zIndex:5})

    /*.on('mouseover',function(){

     this.setSize(2.5);

    })

    .on('mouseout',function(){          

     this.setSize(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.jianjuY).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个 或者前面的都为null 修改起点坐标

      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.jianjuY).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.jianjuY),

         L,

         x,

         y         

        ]);

       }else{

        areaPath.push(x);

        areaPath.push(y);

       }

       

       //如果是最后一个点

       if(n === l - 1){ 

        areaPath.push(x);

        areaPath.push(parseInt(draw.startY-draw.jianjuY));

       }

       //画点

       self.baseDraw[o.dotType || 'circle'](self,{

        x : x,     

        y : y,

        r : 4,

        fillColor : o.color

       })

       .attr({data:data[n],pos:x+'-'+(y-5)})

       .on('mouseover',(function(o,x,y){

        return function(){

         if(self.currList.dot){

          if(self.currList.dot[0] === this[0])

           return;

          self.currList.dot.setSize(0);

          self.currList.line.setSize(1.5);

         }

         this.setSize(2);

         line.setSize(2.5);

         var pos = this.attr('pos').split('-');

         self.showTooltip(o,pos[0],pos[1],this.attr('data'));

         self.currList.dot  = this;

         self.currList.line = line;

        }            

       

       })(o,x,y))

       /*.on('mouseout',function(){

        this.setSize(0);

        line.setSize(1.5);

        //self.hideTooltip()

       })*/

       .on('click',function(){areaGroup.toFront(); }) 

       .css({zIndex:10,cursor:'pointer'})

       .appendTo(areaGroup);

       

     }

    }

    areaPath.push(seal)

    self.baseDraw.path(self,{

     border      : 0,

     isfill      : true,

     fillColor   : o.color,

     opacity     : 0.5,

     path        : areaPath

    })

    .css({zIndex:5})

    .appendTo(areaGroup);

    

    line = self.baseDraw.path(self,{

     border      : 1.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-draw.jianjuY).toFixed(0)),

       height = Number((data[j] * (draw.yPices / draw.feed)-draw.jianjuY).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-draw.jianjuY];

     }else{

       var x     = Number((draw.startX+draw.jianjuX).toFixed(0)),

         width = Number((data[j]*((draw.xPices / draw.feed))-draw.jianjuX).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+draw.jianjuX+width/2,y];

     }

     self.baseDraw.path(self,{

      border      : 0,

      isfill      : true,

      fillColor   : o.color,

      opacity     : 1,

      path        : path

     })

     .attr({data:data[j],pos:pos[0]+'-'+pos[1]})

     .css({zIndex:5,cursor:'pointer'})    

     .on('mouseover',(function(d){

             

       return function(){         

         this.setOpacity(0.85); 

         var pos= this.attr('pos').split('-')

         self.showTooltip(o,pos[0],pos[1],this.attr('data'));        

       }

       

      })(data[j])

     )

     .on('mouseout',function(){

      this.setOpacity(1); 

     })

     .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(self,{

     config  : opts.chartData[i],

     s       : start,

     e       : end,

     r       : radiu,

     innerR  : 0

    })    

    .css({zIndex:5,cursor:'pointer'})

    .attr({move:moveDisplacement,pos:dot[0]+'-'+dot[1]})

    .on('mouseover',function(){      

     this.setOpacity(0.85);

     var pos = this.attr('pos').split('-');

     self.showTooltip(opts.chartData[i],pos[0],pos[1],((e-s)/360*100).toFixed(0)+'%')

    })

    .on('mouseout',function(e){

     var elem = e.toElement || e.relatedTarget;

     //如果碰到里面的文本 或者是提示框  不消失

     if(!elem||contains(this[0].parentNode,elem)||contains(self.tipC[0],elem))

      return;

     self.hideTooltip(); 

     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(self,{

      x    : x,

      y    : y,

      fill : '#fff',

      'text-anchor':'left'

     })

     .css({

       fontFamily : 'Verdana,Arial,Helvetica,sans-serif',

       fontSize   : '12px',

       position   : 'absolute',

       color      : '#fff',

       cursor     : 'pointer',

       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;

   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,

      id    = 'chart'+j,

      piesGroup = self.mainGroup[id]?self.mainGroup[id].chart:self.group(id).appendTo();      

     !self.mainGroup[id]

      &&(self.mainGroup[id] = {chart:piesGroup,show:true});        

     inc = inc + value;

     var name = o.name,

      size = calTextLen(name),

      dot  = angle(radiu,[rx,ry],s+(e-s)/2,2),

      showDot = angle(radiu- Rpice * i,[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(self,{

      config  :  o,

      s       :  start,

      e       :  end,

      r       :  outR,

      innerR  :  innerR

     })

     .attr({m :  i+'-'+j,data:((e-s)/360*100).toFixed(0)+'%',pos:showDot[0]+'-'+showDot[1]})

     .css({zIndex:5,cursor:'pointer'})

     .on('mouseover',function(){

      this.setOpacity(0.85);

      var pos = this.attr('pos').split('-');

      self.showTooltip(o,pos[0],pos[1],this.attr('data'))

     })

     .on('mouseout',function(e){

      var elem = e.toElement || e.relatedTarget;

      if(!elem||elem.getAttribute('m')===this[0].getAttribute('m'))

       return;           

      this.setOpacity(1);

     })     

     .appendTo(piesGroup);

     self.baseDraw.span(self,{

       x    : x,

       y    : y,

       fill : '#fff',

       'text-anchor':'left'

      })

      .attr({m :  i+'-'+j})

      .css({

        fontFamily : 'Verdana,Arial,Helvetica,sans-serif',

        fontSize   : '12px',

        position   : 'absolute',

        color      : '#fff',

        cursor     : 'pointer',

        zIndex     : 10

      })

      .addText(name)

      .appendTo(piesGroup);

    });

  

   });

  },

  drawSegment  : function(){

 

   var self = this,

    opts = this.opts, 

    draw = opts.draw, 

    chartData  = opts.chartData,

    typeIsX    = opts.charts.panel==='x',

    columnPad  = 5,

    prev       = [],

    columnSize = ~~(typeIsX?draw.xPices:draw.yPices) - columnPad * 2;

   each(chartData,function(i,c){

    if(i in self.hideList)

     return;

     

    var id    = 'chart' + i,

     segmentGroup = self.mainGroup[id]?self.mainGroup[id].chart:self.group(id).appendTo();

     

    self.mainGroup[id] = {chart : segmentGroup,show : true};

    

    each(c.data,function(j,d){

     if(d===null||d===0)

      return;

     

     if(typeIsX){

      var start  = draw.startX + columnPad,

       x      = ~~(start + j*draw.xPices).toFixed(0),

       y      = ~~(draw.startY-(prev[j]?prev[j]:0)).toFixed(0),

       size   = ~~(d*draw.yPices / draw.feed ).toFixed(0),

       path   = [

        M,

        x,

        y,

        L,

        x,

        y - size,

        L,

        x + columnSize,

        y - size,

        L,

        x + columnSize,

        y,

        seal

       ];

      var pos = [x + columnSize/2,y-size]; 

     }else{

      var start  = draw.startY - columnPad,

       x      = ~~(draw.startX+(prev[j]?prev[j]:0)).toFixed(0) ,

       y      = ~~(start- j*draw.yPices).toFixed(0),

       size   = ~~(d*draw.xPices / draw.feed ).toFixed(0),

       path   = [

        M,

        x,

        y,

        L,

        x + size,

        y ,

        L,

        x + size,

        y - columnSize,

        L,

        x ,

        y - columnSize,

        seal

       ];

      var pos = [x+size/2,y - columnSize]; 

     }

     self.baseDraw.path(self,{

      border      : 0,

      isfill      : true,

      fillColor   : c.color,

      opacity     : 1,

      path        : path

     })

     .attr({data:d,pos:pos[0]+'-'+pos[1]})

     .on('mouseover',function(){            

      this.setOpacity(0.85);

      var pos = this.attr('pos').split('-');

      self.showTooltip(chartData[i],pos[0],pos[1],this.attr('data'))      

     })

     .on('mouseout',function(){

      this.setOpacity(1);

     })      

     .css({zIndex:5,cursor:'pointer',left:'0px',top:'0px'})    

     .appendTo(segmentGroup);

     prev[j]

      ? prev[j] = prev[j] + size

      : prev[j] = size;

    });

   });

  },

  baseDraw  : {

   rect : function(o,config){

    return o.createElement('rect')

     .attr({

      rx             : config.arc*30 || 5,

      ry             : config.arc*30 || 5,

      width          : config.width  || 50,

      height         : config.height || 50,

      fill           : config.fill   || '#fff',

      'fill-opacity' : config.opacity || 0.85,

      'stroke-width' : config.border  || 2,

      stroke         : config.borderColor  || '#606060',

      transform      : 'translate('+(config.left||0)+','+(config.top||0)+')'

     }); 

   },

   text : function(o,config){

    return o.createElement('text')

     .attr(config);

   },

   span : function(o,config,v){

    return o.createElement('text')

     .attr(config)

     .attr({

      y : config.y+(v||15)

     });

   },

   path : function(o,config){

    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 o.createElement('path')

     .attr(set);

   },

   circle : function(o,config){

    var set  = {};

    set.cx   = config.x;

    set.cy   = config.y;

    set['stroke-width'] = 0;

    set.stroke = config.borderColor || '#C0C0C0';

    set.r    = config.r;

    set.fill = config.fillColor;

    return o.createElement('circle')

     .attr(set); 

   },

   square : function(o,config){  

    var x    = config.x,

     y    = config.y,

     r    = config.r,

     color= config.fillColor,

     len  = r,

     path = [

      M,

      (x-len).toFixed(0),

      (y-len).toFixed(0),

      L,

      (x+len).toFixed(0),

      (y-len).toFixed(0),

      (x+len).toFixed(0),

      (y+len).toFixed(0),

      (x-len).toFixed(0),

      (y+len).toFixed(0),

      seal

     ];

     return o.baseDraw.path(o,{

      border      : 1,

      borderColor : color,

      isfill      : true,

      fillColor   : color,

      path        : path     

     });    

   },

   triangle : function(o,config){

    var x     = config.x,

     y     = config.y,

     r     = config.r+0.1,

     color = config.fillColor,

     path  = [

      M,

      x.toFixed(0),

      (y-1.33*r).toFixed(0),

      L,

      (x+r).toFixed(0),

      (y+0.67*r).toFixed(0),

      (x-r).toFixed(0),

      (y+0.67*r).toFixed(0),

      seal

     ];

    return o.baseDraw.path(o,{

     border      : 1,

     borderColor : color,

     isfill      : true,

     fillColor   : color,

     path        : path     

    });       

   },

   diamond : function(o,config){

    var x     = config.x,

     y     = config.y,

     r     = 1.35*config.r,

     color = config.fillColor,

     path  = [

      M,

      x.toFixed(0),

      (y-r).toFixed(0),

      L,

      (x+r).toFixed(0),

      y.toFixed(0),

      x.toFixed(0),

      (y+r).toFixed(0),

      (x-r).toFixed(0),

      y.toFixed(0),

      seal

     ];

    return o.baseDraw.path(o,{

     border      : 1,

     borderColor : color,

     isfill      : true,

     fillColor   : color,

     path        : path     

    });       

   },

   pie    : function(o,config){

    //config,s,e,r,index

    var opts     = o.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 o.baseDraw.path(o,{

     border      : 1,

     border      : '#fff',

     isfill      : true,

     fillColor   : color,

     opacity     : 1,

     path        : path

  

    })

  

   } 

  }

 };

 

//---------------------------------------------------------------------------------------------------

//如果是vml 修改smipleChart.prototype中的一些方法

 !hasSVG 

  &&extend(smipleChart.prototype.baseDraw,{

   rect : function(o,config){  

    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 o.createElement('roundrect')

     .attr(attr)

     .css(css);

   },

   text : function(o,config){

    return o.createElement('TextBox')

     .attr({inset : "2px,2px,2px,2px" })

     .css({zIndex:200})

   },

   span : function(o,config){

    return o.createElement('span').

     css({

      position:'absolute',

      left : config.x+'px',

      top  : config.y+'px'

     })

   },

   path : function(o,config){   

    var attr   = {},

     width  = o.width,

     height = o.height,

     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 = o.createElement()

     .attr(attr)

     .css(css);

    if(config.opacity){

     var fill =  o.createElement('fill')

      .attr({

       type     : 'fill',

       color    : config.fillColor||"#C0C0C0",

       opacity  : config.opacity

      })

      .appendTo(elem);

     //那这个对象的一个属性引用设置透明的元素 以后会用到

     elem.opacity = fill[0];

    }      

    return elem;

     

   },

   circle : function(o,config){

    var width  = o.width,

     height = o.height,

     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 o.createElement()

     .attr(attr)

     .css(css) 

   },

   pie   : function(o,config){

    ////config,s,e,r,index

    

    var opts  = o.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 o.baseDraw.path(o,{

     border      : 1,

     border      : '#fff',

     isfill      : true,

     fillColor   : color,

     opacity     : 1,

     path        : path     

    })

    

   } 

  });

//---------------------------------------------------------------------------------------------------

})(document);

 window.onload = function(){

  var t = new Date().getTime();

 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',

    dotType : 'square',

    //data    : [11,12,13,15,16,18,17,14,10]

    //[1,2,3,5,6,8,7,4,10]

    data: [44,-12,-78,100,-13,-4,-26,34]

   }, {

 

    name: 'frfr',

    color: '#AA4643',

    dotType : 'triangle',    

    data: [-44,12,78,-100,13,4,-56,-34]

   }, {

    name: 'AAAAA',

    color: '#89A54E',

    dotType : 'diamond',

    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 ='区域图表侧标题'

  config.chartData = [

   {

    name    : 'xcv',

    color   : '#4572A7',

    //data    : [0,3,4,5,6,7,8,9,10,11]

    data    : [11,12,13,14,15,16,-17,18,19,0] 

   }, {

 

    name: 'frfr',

    color: '#AA4643',   

    data: [44,12,78,100,13,44,56,34]

   }, {

    name: 'AAAAA',

    color: '#89A54E',

    data: [null,101,83,null,22,78,88,44,78]

   }, {

    name: 'BBBB',

    color: '#80699B',

    data: [null, 58, 35, null, 52, 47, 26, 55, 39, 123,15,66]

   }

   ]

   

  new smipleChart($$('area'),config);

  config.title.text ='柱状图表'

  config.subTitle.text='柱状图表副标题'

  config.yUnit.text ='柱状图表侧标题'  

  config.charts.type ='columns';

  config.chartData =[

   {

    name  : 'xcv',

    color : '#4572A7',

    //data  : [2,3,4,5,6,7,8,9,10,11]

    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,411] 

   }, {

    name: 'ccc',

    color: '#89A54E',

    data: [55,null,75,233] 

   }, {

    name: 'ddd',

    color: '#80699B',

    data: [63,null,100,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= [290,400]  

  new smipleChart($$('pies'),config);  

  config.chartData =[

   {

    name  : 'xcv',

    color : '#4572A7',

    data  : [111,222,333,null,444,555,56,57,84] 

   }, {

    name: 'frfr',

    color: '#AA4643',

    data: [845,666,100,null,666,677,56,88,633,55,555] 

   }, {

    name: 'AAAAA',

    color: '#89A54E',

    data: [555,162,75,null,364,0,637,112,163,615] 

   }

   ]

  

  config.charts.type ='line';

  config.legend.pos= [10,10]

  //

  config.yUnit.lineNum = 10;

  config.charts.panel = 'x';

  config.title.text ='分段图表'

  config.subTitle.text='分段图表副标题'

  config.yUnit.text ='分段图表侧标题'  

  config.charts.type ='segment';

  new smipleChart($$('segmentx'),config);

  config.charts.panel = 'y';

  new smipleChart($$('segmenty'),config);

  config.yUnit.lineNum = 2;

  config.title.text ='比较小的'

  config.subTitle.text='只设置了2条线'

  config.yUnit.text ='小测标题' ; 

  new smipleChart($$('vv'),config);

  //alert(new Date().getTime()-t)

 }

</script>

</body>

</html>

js浮点精度问题 不好解决 求助。。。。。。。。。

水平有限 难免问题多多 望赐教。。。。。。。

Javascript 相关文章推荐
基于jquery的超简单上下翻
Apr 20 Javascript
深入理解JavaScript作用域和作用域链
Oct 21 Javascript
js中 关于undefined和null的区别介绍
Apr 16 Javascript
jQuery实现复选框批量选择与反选的方法
Jun 17 Javascript
JavaScript实现可拖拽的拖动层Div实例
Aug 05 Javascript
基于jQuery实现动态数字展示效果
Aug 12 Javascript
跟我学习javascript的this关键字
May 28 Javascript
最好用的Bootstrap fileinput.js文件上传组件
Dec 12 Javascript
javascript实现简易计算器
Feb 01 Javascript
js浏览器滚动条卷去的高度scrolltop(实例讲解)
Jul 07 Javascript
解决JSON.stringify()自动将中文转译成unicode的问题
Jan 05 Javascript
初试vue-cli使用HBuilderx打包app的坑
Jul 17 Javascript
原生javascript实现简单的datagrid数据表格
Jan 02 #Javascript
浅谈jQuery事件绑定原理
Jan 02 #Javascript
js+jquery实现图片裁剪功能
Jan 02 #Javascript
javascript 构造函数方式定义对象
Jan 02 #Javascript
深入探寻javascript定时器
Jan 02 #Javascript
JavaScript中的Truthy和Falsy介绍
Jan 01 #Javascript
JavaScript中的null和undefined区别介绍
Jan 01 #Javascript
You might like
深入浅出讲解:php的socket通信原理
2016/12/03 PHP
解决laravel 表单提交-POST 异常的问题
2019/10/15 PHP
js select常用操作控制代码
2010/03/16 Javascript
JQuery触发radio或checkbox的change事件
2012/12/18 Javascript
jquery 使用简明教程
2014/03/05 Javascript
node.js中的querystring.parse方法使用说明
2014/12/10 Javascript
jQuery使用之处理页面元素用法实例
2015/01/19 Javascript
angularjs学习笔记之简单介绍
2015/09/26 Javascript
jQuery实现模仿微博下拉滚动条加载数据效果
2015/12/25 Javascript
javascript的BOM
2016/05/03 Javascript
jQuery遍历json的方法(推荐)
2016/06/12 Javascript
jquery二级目录选中当前页的css样式
2016/12/08 Javascript
详解Vue路由开启keep-alive时的注意点
2017/06/20 Javascript
详解a++和++a的区别
2017/08/30 Javascript
vue.js实例对象+组件树的详细介绍
2017/10/20 Javascript
vue组件父与子通信详解(一)
2017/11/07 Javascript
微信小程序实现验证码获取倒计时效果
2018/02/08 Javascript
说说node中的可读流和可写流的区别
2018/06/01 Javascript
查找Vue中下标的操作(some和findindex)
2020/08/12 Javascript
vue移动端写的拖拽功能示例代码
2020/09/09 Javascript
Python卸载模块的方法汇总
2016/06/07 Python
Python模块包中__init__.py文件功能分析
2016/06/14 Python
教你使用python画一朵花送女朋友
2018/03/29 Python
python读取xlsx的方法
2018/12/25 Python
Python Django框架防御CSRF攻击的方法分析
2019/10/18 Python
python中利用matplotlib读取灰度图的例子
2019/12/07 Python
python实现贪吃蛇双人大战
2020/04/18 Python
Python with语句用法原理详解
2020/07/03 Python
如何用 Python 制作一个迷宫游戏
2021/02/25 Python
玩具反斗城天猫官方旗舰店:享誉全球的玩具店
2017/10/10 全球购物
初一新生军训方案
2014/05/22 职场文书
建筑工程质量通病防治方案
2014/06/08 职场文书
优秀团员事迹材料1500字
2014/08/31 职场文书
“三支一扶”支教教师思想汇报
2014/09/13 职场文书
POST提交数据常见的四种方式
2022/01/18 HTML / CSS
Golang 并发编程 SingleFlight模式
2022/04/26 Golang