javascript smipleChart 简单图标类_Javascript教程-查字典教程网
javascript smipleChart 简单图标类
javascript smipleChart 简单图标类
发布时间:2016-12-30 来源:查字典编辑
摘要:因为编辑器会对代码有所破坏,所以提供一个在线演示http://demo.jb51.net/chengxu/smipleChart.htm复制...

因为编辑器会对代码有所破坏,所以提供一个在线演示

http://demo.jb51.net/chengxu/smipleChart.htm

复制代码 代码如下:

<!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'></div>

<div id='area'></div>

<div id='zhu'></div>

<div id='zhu1'></div>

<div id='pie'></div>

<div id='pies'></div>

<div id='segment'></div>

<div id='vv'></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+'>');

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>

相关阅读
推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
  • 大家都在看
  • 小编推荐
  • 猜你喜欢
  • 最新Javascript教程学习
    热门Javascript教程学习
    编程开发子分类