1. 程式人生 > >前端fabric.js實現二叉樹視覺化佈局

前端fabric.js實現二叉樹視覺化佈局

2.效果圖

3.程式碼

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
* {
	margin: 0;
	padding: 0;
}

html, body {
	height: 100%;
	width: 100%;
}

canvas {
	display: block;
}
</style>
</head>
<body>
	<div id="divcanvas">
		<canvas id="canvas" width="974" height="715"></canvas>
	</div>
</body>
<script src="fabric.min.js"></script>
<script src="jquery/jquery.min.js"></script>
<script>
	var contrydata = {
		name : "浙江省上城區上城區",
		cenNum : 19,
		color : '#D0D0D0',
		childData : [ {
			name : "杭州市",
			color : '#0C64FC',
			cenNum : 10,
			childData : [ {
				color : '#D0D0D0',
				cenNum : 2,
				name : "上城區上城區上城區上城區上城區"
			}, {
				color : '#D0D0D0',
				cenNum : 2,
				name : "下城區"
			}, {
				color : '#D0D0D0',
				cenNum : 2,
				name : "蕭山區"
			}, {
				color : '#D0D0D0',
				cenNum : 2,
				name : "濱江區"
			}, {
				color : '#D0D0D0',
				cenNum : 2,
				name : "江乾區"
			} ]
		}, {
			name : "寧波市上城區上城區上城區上",
			color : '#D0D0D0',
			cenNum : 4,
			childData : [ {
				color : '#D0D0D0',
				cenNum : 4,
				name : "海曙區",
				childData : [ {
					color : '#D0D0D0',
					cenNum : 2,
					name : "上城區上城區上城區上城區上城區上城區"
				}, {
					color : '#D0D0D0',
					cenNum : 2,
					name : "下城區上城區上城區上城區上城區上區上城區上區上城區上區上城區"
				}]
			} ]
		}, {
			name : "麗水市",
			color : '#D0D0D0',
			cenNum : 5,
			childData : [ {
				color : '#D0D0D0',
				cenNum : 5,
				name : "麗水一區"

			} ]
		} ]
	};
	
$(window).resize(resizeCanvas);  
   
 function resizeCanvas() {  
   		var c=document.getElementById("canvas");
        $(c).attr("width", $(window).get(0).innerWidth);  
   
       $(c).attr("height", $(window).get(0).innerHeight);  
   
        c.getContext("2d").fillRect(0, 0, $(c).width(),  $(c).height());  
   
 };  
   
 resizeCanvas(); 
 	var w_h = $(window).get(0).innerHeight;
 	var w_w = $(window).get(0).innerWidth;
 	
	var LINE_LENGTH = 30/974*w_w;//線長度
	var FONT_SIZE = 10/974*w_w;//字型大小
	var RECT_WIDTH = 100/974*w_w;
	var RECT_HEIGHT = 30/715*w_h;
	var RECT_BCOLOR_NO = '#D0D0D0';//不可選城市顏色
	var RECT_BCOLOR_YES = '#0C64FC';//可選城市顏色
	var dataposition=  [];
	window.onload = function() {
		var rootl = 150;
		var roott = 50;
		var citys = contrydata.citys;

		var canvas = new fabric.Canvas('canvas');
		drawRectAndTextGroup(canvas, rootl, roott, contrydata.color,
				contrydata.name);
		dataposition.push({left:rootl,top:roott,name:contrydata.name});	
		drawData(canvas, rootl, roott, contrydata);
		canvas.on({
			'mouse:down' : function(options) {
				console.log(options.e.clientX + "," + options.e.clientY);
				var oleft = options.e.clientX;
				var otop = options.e.clientY;
				for(var i=0;i<dataposition.length;i++){
					var dp = dataposition[i];
					if(oleft>=dp.left && oleft<=dp.left+RECT_WIDTH && otop>=dp.top&&otop<=dp.top+RECT_HEIGHT){
						alert(dp.name);
					}
				}
			}
		});

	}

	function drawData(canvas, rootleft, rootTop, rootData) {
		var childData = rootData.childData;
		if (childData == undefined || childData == null)
			return;
		var childlen = childData.length;
		var yuanheght = 0;
		
		for (var i = 0; i < childlen; i++) {
			var child = childData[i];
			var cen = child.cenNum;
			var childLeft = rootleft + LINE_LENGTH * 2 + RECT_WIDTH;
			var childTop = rootTop + yuanheght;
			yuanheght += cen * LINE_LENGTH;
			
			dataposition.push({left:childLeft,top:childTop,name:child.name});	
			
			drawRectAndTextGroup(canvas, childLeft, childTop, child.color,
					child.name);
			
			/*var r_w = RECT_WIDTH;
			if(r_w<FONT_SIZE*(tc.length)){
				r_w = FONT_SIZE*(tc.length);
			}*/

			//橫線
			if (i == 0) {
				drawLateralLine(canvas, childLeft - LINE_LENGTH * 2, childTop
						+ RECT_HEIGHT / 2);
			}
			drawLateralLine(canvas, childLeft - LINE_LENGTH * 1, childTop
					+ RECT_HEIGHT / 2);

			if (i == childlen - 1) {
				for (var k = 0; k < rootData.cenNum - cen; k++)
					drawHorrentLine(canvas,
							rootleft + LINE_LENGTH + RECT_WIDTH, rootTop
									+ RECT_HEIGHT / 2 + k * LINE_LENGTH);
			}

			var cchild = child.childData;
			if (cchild != undefined && cchild != null && cchild.length > 0) {

				drawData(canvas, childLeft, childTop, child);
			}
		}
	}

	/**
	1:left
	t:top
	bcolor:方形背景顏色
	tc:文字內容
	 */
	function drawRectAndTextGroup(canvas, l, t, bcolor, tc) {
		var r_w = RECT_WIDTH;
		if(r_w<FONT_SIZE*(tc.length)){
			r_w = FONT_SIZE*(tc.length);
		}
		var rect = new fabric.Rect({
			width : r_w,
			height : RECT_HEIGHT,
			fill : bcolor,
			originX : 'center',//調整中心點的X軸座標
			originY : 'center',//調整中心點的Y軸座標
		});
		var text = new fabric.Text(tc, {
			hasControls : false,
			fill : "black",
			fontFamily : 'pokeText',
			fontSize : FONT_SIZE,
			originX : 'center',
			originY : 'center'

		});

		//進行組合
		var group = new fabric.Group([ rect, text ], {
			left : l,
			top : t,
			hasControls : false, //選中時是否可以放大縮小
			hasRotatingPoint : false,//選中時是否可以旋轉
			hasBorders : false,//選中時是否有邊框
			transparentCorners : true,
			perPixelTargetFind : true,//預設false。當設定為true,物件的檢測會以像互點為基礎,而不是以邊界的盒模型為基礎。
			selectable : true,//是否可被選中
			lockMovementX : true,//X軸是否可被移動(true為不可,因為字首是lock)
			lockMovementY : true
		//Y軸是否可被移動(true為不可,因為字首是lock)
		})
		
		canvas.add(group);//方塊文字組合塊
		
	}
	/**
	橫線
	 */
	function drawLateralLine(canvas, l, t) {
		var line = new fabric.Line([ l, t, l + LINE_LENGTH, t ], {//橫線
			//終止位置,線長,起始位置,top,這裡是從專案中截下來的我用了變數代替,你要用的話lineheight和lineleft用自己的變數或者數字代替。如果兩個終止位置和起始位置的數值一樣那麼這個線條會垂直,這個應該很好理解。
			fill : '#5E2300',//填充顏色
			stroke : '#5E2300',//筆觸顏色
			strokeWidth : 1,//筆觸寬度
			hasControls : false, //選中時是否可以放大縮小
			hasRotatingPoint : false,//選中時是否可以旋轉
			hasBorders : false,//選中時是否有邊框
			transparentCorners : true,
			perPixelTargetFind : true,//預設false。當設定為true,物件的檢測會以像互點為基礎,而不是以邊界的盒模型為基礎。
			selectable : true,//是否可被選中
			lockMovementX : true,//X軸是否可被移動(true為不可,因為字首是lock)
			lockMovementY : true
		//Y軸是否可被移動(true為不可,因為字首是lock)
		});
		canvas.add(line);
	}
	function drawHorrentLine(canvas, l, t) {
		var line = new fabric.Line([ l, t, l, t + LINE_LENGTH ], {//豎線
			//終止位置,線長,起始位置,top,這裡是從專案中截下來的我用了變數代替,你要用的話lineheight和lineleft用自己的變數或者數字代替。如果兩個終止位置和起始位置的數值一樣那麼這個線條會垂直,這個應該很好理解。
			fill : '#5E2300',//填充顏色
			stroke : '#5E2300',//筆觸顏色
			strokeWidth : 1,//筆觸寬度
			hasControls : false, //選中時是否可以放大縮小
			hasRotatingPoint : false,//選中時是否可以旋轉
			hasBorders : false,//選中時是否有邊框
			transparentCorners : true,
			perPixelTargetFind : true,//預設false。當設定為true,物件的檢測會以像互點為基礎,而不是以邊界的盒模型為基礎。
			selectable : true,//是否可被選中
			lockMovementX : true,//X軸是否可被移動(true為不可,因為字首是lock)
			lockMovementY : true
		//Y軸是否可被移動(true為不可,因為字首是lock)
		});
		canvas.add(line);
	}
</script>

</html>