svg 生成柱形图 和饼图
备注:直接生成svg代码 不操作dom 可用于java调用js函数直接生成柱形图和饼图数据,完成后台生成报表功能
效果图
//生成随机数据
var rand=function(size){
var data=[];
for(var i=0;i<size;i++){
data.push(Math.random()*100);
}
return data;
}
document.getElementById("app").innerHTML=toChar({
xAxis:['2020','20测2测1第三方','2022','2023','2024',"1234","5641","2015"],
data:{
"计算1":{
type:"line",
data:rand(10)
},
"计算2":{
type:"bar",
data:rand(10)
},
"计算3":{
type:"bar",
data:rand(10)
}
}
})
document.getElementById("app").innerHTML=toPie({
data:{
"测试":50,
"asd":100
}
});
甘特图
document.getElementById("app").innerHTML=
toGantt(
{
bgColor:'#eff0f0',
xAxis:['2020-01','2020-02','2020-03','2020-04','2020-05','2020-06','2020-07','2020-08','2020-09'],
data:[
{
name:"啊",
data:[
{
b:1,
e:4,
text:"啊是"
},
{
b:2,
e:3
},
{
b:2,
e:3
}
]
},
{
name:"456",
data:[
{
b:0,
e:3
},
{
b:2,
e:3
},
{
b:2,
e:3
}
]
},
{
name:"789",
data:[
{
b:0,
e:8
},
{
b:2,
e:3
},
{
b:2,
e:3
}
]
},
{
name:"234",
data:[
{
b:1,
e:4
}
]
},
{
name:"ghfg",
data:[
{
b:1,
e:4
}
]
},
]
});
引用js
var strToFunction=function(tpl){
var reg = /{{([^}}]+)?}}/g,
regOut = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
code = 'var r=[];\n var opt=data.opt;',
cursor = 0;
var add = function(line, js) {
js? (code += line.match(regOut) ? line + '\n' : 'r.push(' + line + ');\n') :
(code += line != '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '');
return add;
}
while(match = reg.exec(tpl)) {
add(tpl.slice(cursor, match.index))(match[1], true);
cursor = match.index + match[0].length;
}
add(tpl.substr(cursor, tpl.length - cursor));
code += 'return r.join("");';
return new Function("data",code.replace(/[\r\t\n]/g, ''));
}
var maps={
line:strToFunction(" <line x1='{{opt.x}}' y1='{{opt.y}}' x2='{{opt.x1}}' y2='{{opt.y1}}' style='stroke:{{opt.color}};stroke-width:1' />"),
block:strToFunction("<rect fill='{{opt.fill}}' x='{{opt.x}}' y='{{opt.y}}' width='{{opt.width}}' height='{{opt.height}}' />"),
g:strToFunction('<g transform="translate({{opt.x}},{{opt.y}})">{{opt.html}}</g>'),
text:strToFunction('<text x="{{opt.x}}" y="{{opt.y}}" style="font-size:12px" fill="{{opt.fill}}" >{{opt.text}}</text>'),
path:strToFunction('<path d="{{opt.value}}" stroke="{{opt.color}}" fill="{{opt.color}}"; ></path>'),
};
var util={
sum:function(data){
var result=0;
for(var i=0;i<data.length;i++){
result+=data[i];
}
return result;
},
calcFont:function(val){
return val.length*9;
},
findMax:function(data){
var max=null;
for(var i=0;i<data.length;i++){
if(!max){
max=data[i]
}else if(data[i]>max){
max=data[i];
}
}
return max;
},
toSvg:function(data,opt){
var rate={
x:"width",
x1:"width",
y:"height",
y1:"height",
width:"width",
height:"height"
};
var _to=function(list,pdata){
var svg="";
for(var i=0;i<list.length;i++){
var item=list[i];
if(pdata){
for(var name in rate){
if(typeof(item.opt[name])=="string"&&
item.opt[name].indexOf("%")!=-1&&
pdata.opt[rate[name]]
){
var value=item.opt[name];
value=value.substring(0,value.length-1)-0;
item.opt[name]=(value/100)*pdata.opt[rate[name]];
}
}
}
if(item.childs){
item.opt.html=_to(item.childs,item);
}
if(maps[item.type]){
svg+=maps[item.type](item);
}
}
return svg;
}
return "<svg width='"+opt.width+"' height='"+opt.height+"' xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" >"+_to(data)+"</svg>";
}
};
var toGantt=function(opt){
var defaults={
bgColor:"#fff",
height:400,
width:800,
paading:{
left:20,
right:50,
bottom:20,
top:20
},
xItems:{
width:45,
height:40
},
yPoint:{
width:30
},
bottom:{
height:30
},
colors:['#37a2da','#32c5e9','#9fe6b8','#ffdb5c','#ff9f7f','#fb7293','#e7bcf3']
};
for(var i in opt){
defaults[i]=opt[i];
}
var content={
type:"g",
opt:{
x:defaults.paading.left,
y:defaults.paading.top,
height:defaults.height-(defaults.paading.top+defaults.paading.bottom),
width:defaults.width-(defaults.paading.left+defaults.paading.right)
},
childs:[]
};
var bgColor={
type:"block",
opt:{
x:0,
y:0,
width:defaults.width,
height:defaults.height,
fill:defaults.bgColor
}
};
var yPoint={
type:"g",
opt:{
x:0,
y:0,
width:defaults.yPoint.width,
height:content.opt.height-defaults.bottom.height
},
childs:[]
}
var bottom={
type:"g",
opt:{
x:defaults.yPoint.width,
y:content.opt.height-(defaults.bottom.height),
width:content.opt.width-defaults.yPoint.width,
height:defaults.bottom.height
},
childs:[]
};
var yContent={
type:"g",
opt:{
x:defaults.yPoint.width,
y:0,
width:content.opt.width-defaults.yPoint.width,
height:content.opt.height-defaults.bottom.height
},
childs:[]
}
content.childs.push(yContent);
content.childs.push(yPoint);
content.childs.push(bottom);
//绘画左侧 文字和 - 存放到 yPoint中
yPoint.childs.push({
type:'line',
opt:{
x:yPoint.opt.width,
x1:yPoint.opt.width,
y:0,
y1:yPoint.opt.height,
color:"#000"
}
})
for(var i=0;i<defaults.data.length;i++){
var yHeight=yPoint.opt.height/defaults.data.length;
var yWidth=yPoint.opt.width;
var fontSize=yHeight/2;
if(fontSize<0){
fontSize=0;
}
yPoint.childs.push({
type:"line",
opt:{
x:yWidth-5,
y:i*yHeight,
x1:yWidth,
y1:i*yHeight,
color:"#000"
}
});
// yContent.childs.push({
// type:'line',
// opt:{
// x:0,
// y:i*yHeight,
// x1:"100%",
// y1:i*yHeight,
// color:"#ccc"
// }
// });
yPoint.childs.push({
type:"text",
opt:{
y:i*yHeight+fontSize,
x:0,
fill:"#000",
text:defaults.data[i].name
}
});
}
bottom.childs.push({
type:'line',
opt:{
x:0,
x1:'100%',
y:0,
y1:0,
color:"#000"
}
})
for(var i=0;i<defaults.xAxis.length;i++){
var xWidth=bottom.opt.width/defaults.xAxis.length;
bottom.childs.push({
type:'line',
opt:{
x:(xWidth*(i+1)),
x1:(xWidth*(i+1)),
y:0,
y1:10,
color:"#000"
}
});
var x=util.calcFont(defaults.xAxis[i]);
bottom.childs.push({
type:"text",
opt:{
y:20,
x:(xWidth*(i))+((xWidth-x)/2),
fill:"#000",
text:defaults.xAxis[i]
}
});
// yContent.childs.push({
// type:'line',
// opt:{
// x:(xWidth*(i+1)),
// x1:(xWidth*(i+1)),
// y:0,
// y1:'100%',
// color:"#ccc"
// }
// });
}
for(var i=0;i<defaults.data.length;i++){
var list=defaults.data[i].data;
var xWidth=bottom.opt.width/defaults.xAxis.length;
var xHeight=yContent.opt.height/defaults.data.length;
var length=list.length;
for(var q=0;q<length;q++){
var color=list[q].color?list[q].color:defaults.colors[q%defaults.colors.length];
yContent.childs.push({
type:"block",
opt:{
x: list[q].b*xWidth+(xWidth/2),
y:i*xHeight+
(xHeight*0.1) + //上下间距值
(xHeight*(q*0.9/length)) + //每个节点的距离
((xHeight*0.9/length)*0.2) //节点与节点间距 当前节点的大小减去百分之20
,
height:10,
width: (list[q].e-list[q].b)*xWidth,
fill:color
}
});
if(list[q].text){
yContent.childs.push({
type:"text",
opt:{
x: list[q].b*xWidth+(xWidth/2)+(list[q].e-list[q].b)*xWidth +10,
y:i*xHeight+
(xHeight*0.1) + //上下间距值
(xHeight*(q*0.9/length)) + //每个节点的距离
((xHeight*0.9/length)*0.2) + //节点与节点间距 当前节点的大小减去百分之20
10
,
fill:"#000",
text:list[q].text
}
});
}
}
}
return util.toSvg([bgColor,content],defaults);
}
var toPie=function(opt){
var defaults={
bgColor:"#fff",
paading:20,
width:600,
height:400,
rateSize:0.6,
colors:['#e062ae','#ff9f7f','#ffdb5c','#ffdb5c','#ff9f7f','#fb7293','#e7bcf3'],
xItem:{
lineHeight:20,
width:30
}
};
for(var i in opt){
defaults[i]=opt[i];
}
var content={
type:"g",
opt:{
x:defaults.paading,
y:defaults.paading,
height:defaults.height-(defaults.paading*2),
width:defaults.width-(defaults.paading*2)
},
childs:[]
};
var xItem={
type:"g",
opt:{
x:0,
y:0,
height:"100%",
width:200
},
childs:[]
}
var pie={
type:"g",
opt:{
x:0,
y:0,
height:content.opt.height,
width:content.opt.width
},
childs:[]
}
content.childs.push(pie);
//中心坐标轴
defaults.x=pie.opt.width/2;
defaults.y=pie.opt.height/2;
//圆的半径
defaults.rate=defaults.x*defaults.rateSize;
var getBlock=function(bAngle,eAngle){
var arr=[];
var bPoint=pointe(bAngle);
var ePoint=pointe(eAngle);
arr.push('M '+defaults.x+' '+ defaults.y+' L '+bPoint.x+' '+bPoint.y);
arr.push('A '+defaults.rate+' '+ defaults.rate+' 0 '+(eAngle-bAngle>180?1:0)+' 1 '+ePoint.x+' '+ePoint.y);
arr.push('Z');
return arr.join(' ');
}
//计算sum值
var sum=0;
for(var i in opt.data){
sum+=opt.data[i];
}
function d2a(n){//角度转弧度
return n*Math.PI/180;
}
function pointe(ang){//求坐标函数
return {
x:defaults.x+defaults.rate*Math.sin(d2a(ang)),
y:defaults.y-defaults.rate*Math.cos(d2a(ang))
}
}
var bAngle=0;
var size=0;
for(var i in opt.data){
var rate=opt.data[i]/sum;
var eAngle=bAngle+(360*rate);
var path=getBlock(bAngle,eAngle);
pie.childs.push({
type:"path",
opt:{
value:path,
color:defaults.colors[size%defaults.colors.length]
}
});
xItem.childs.push({
type:"block",
opt:{
x:0,
y:defaults.xItem.lineHeight*size,
width:defaults.xItem.width,
height:15,
fill:defaults.colors[size%defaults.colors.length]
}
});
xItem.childs.push({
type:"text",
opt:{
x:defaults.xItem.width+10,
y:defaults.xItem.lineHeight*size+12,
text:i+"("+(rate*100).toFixed(2)+"%)",
width:defaults.xItem.width,
fill:'#333'
}
});
bAngle=eAngle;
size++;
}
return util.toSvg([content,xItem],defaults);
}
var toChar=function(opt){
var defaults={
bgColor:"#fff",
paading:30,
height:400,
width:800,
xItems:{
width:45,
height:40
},
yPoint:{
width:40
},
bottom:{
height:30
},
colors:['#37a2da','#32c5e9','#9fe6b8','#ffdb5c','#ff9f7f','#fb7293','#e7bcf3']
};
var calcFonts=[];
for(var i in opt){
defaults[i]=opt[i];
}
var bgColor={
type:"block",
opt:{
x:0,
y:0,
width:defaults.width,
height:defaults.height,
fill:defaults.bgColor
}
};
var content={
type:"g",
opt:{
x:defaults.paading,
y:defaults.paading,
height:defaults.height-(defaults.paading*2),
width:defaults.width-(defaults.paading*2)
},
childs:[]
};
//底部文字坐标轴
var bottom={
type:"g",
opt:{
x:defaults.yPoint.width,
y:content.opt.height-(defaults.bottom.height),
width:content.opt.width-defaults.yPoint.width,
height:defaults.bottom.height
},
childs:[]
};
var xItems={
type:"g",
opt:{
x:defaults.yPoint.width,
y:10,
width:defaults.width-(defaults.paading*2),
height:30
},
childs:[]
};
//左侧y轴坐标
var yPoint={
type:"g",
opt:{
x:0,
y:defaults.xItems.height,
width:defaults.yPoint.width,
height:content.opt.height-defaults.bottom.height-defaults.xItems.height
},
childs:[]
}
//内容块
var yContent={
type:"g",
opt:{
x:defaults.yPoint.width,
y:defaults.xItems.height,
width:content.opt.width-defaults.yPoint.width,
height:content.opt.height-defaults.bottom.height-defaults.xItems.height
},
childs:[]
}
content.childs.push(xItems);
content.childs.push(yContent);
content.childs.push(yPoint);
content.childs.push(bottom);
yPoint.childs.push({
type:"line",
opt:{
x:"100%",
y:0,
y1:"100%",
x1:"100%",
color:"#000"
}
})
bottom.childs.push({
type:"line",
opt:{
x:0,
y:0,
x1:"100%",
y1:0,
color:"#000"
}
});
//findMax
var max=[];
var barDataSize=0;
for(var i in defaults.data){
var data=defaults.data[i].data;
calcFonts.push(util.calcFont(i));
if(defaults.data[i].type=='bar'){
barDataSize++;
}
max.push(util.findMax(data));
}
var dataSize=max.length;
max=util.findMax(max);
max=parseInt(max+max/10);
var y=5;
for(var i=0;i<=y;i++){
var rate=(max/y)*i/max*100;
yContent.childs.push({
type:"line",
opt:{
y:yPoint.opt.height*((100-rate)/100),
y1:yPoint.opt.height*((100-rate)/100),
x:0,
x1:"100%",
color:"#ccc"
}
})
yPoint.childs.push({
type:"line",
opt:{
y:yPoint.opt.height*((100-rate)/100),
y1:yPoint.opt.height*((100-rate)/100),
x1:"100%",
x:defaults.yPoint.width-10,
color:"#000"
}
});
yPoint.childs.push({
type:"text",
opt:{
y:yPoint.opt.height*((100-rate)/100)+5,
x:0,
fill:"#000",
text:parseInt(max*(rate/100))
}
});
}
var ywidth=yContent.opt.width /(defaults.xAxis.length);
for(var i=0;i<defaults.xAxis.length;i++){
var item={
type:"g",
opt:{
y:0,
x:ywidth*i,
width:ywidth,
height:"100%"
},
childs:[]
};
var textWidth=util.calcFont(defaults.xAxis[i]);
bottom.childs.push({
type:"line",
opt:{
x:ywidth*(i+1),
y:0,
x1:ywidth*(i+1),
y1:10,
color:"#000"
}
})
bottom.childs.push({
type:"text",
opt:{
y:30,
x:ywidth*i+(ywidth-textWidth)/2,
text:defaults.xAxis[i],
fill:'#000'
},
})
var size=0;
var barStepSize=0;
console.log(barDataSize);
var yy=80/barDataSize;
for(var w in defaults.data){
var value=defaults.data[w].data[i];
var rate=value/max*100;
if(defaults.data[w].type=='line'){
//未到最后一条线
if(i+1<=defaults.xAxis.length){
var nextRate=defaults.data[w].data[i+1]/max*100;
item.childs.push({
type:"line",
opt:{
x: 0,
y:(100-rate)+"%",
x1:"100%",
y1: (100-nextRate)+"%",
color:defaults.colors[size%defaults.colors.length]
}
});
}
}else{
item.childs.push({
type:"block",
opt:{
x: (10+(yy*barStepSize))+"%",
y:(100-rate)+"%",
height:rate+"%",
width: (yy*0.9)+"%",
fill:defaults.colors[size%defaults.colors.length]
}
});
barStepSize++;
}
size++;
}
yContent.childs.push(item)
}
var width=util.sum(calcFonts);
var point=(xItems.opt.width-(width + dataSize * (defaults.xItems.width+15)) )/2;
var i=0;
for(var name in defaults.data){
xItems.childs.push({
type:"text",
opt:{
x:point,
y:0,
text:name,
fill:'#000'
}
});
xItems.childs.push({
type:"block",
opt:{
x:point+calcFonts[i]+10,
y:-13,
width:defaults.xItems.width,
height:xItems.opt.height-15,
fill:defaults.colors[i%defaults.colors.length]
}
});
point+=defaults.xItems.width+calcFonts[i]+15;
i++;
}
return util.toSvg([bgColor,content],defaults);
}