svg 生成柱形图 和 饼图 和 甘特图

本文介绍了一种使用SVG直接生成柱状图、饼图和甘特图的方法,无需DOM操作,适用于Java调用JS函数,实现后台报表自动生成。文中详细展示了如何通过随机数据生成不同类型的图表,并提供了代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值