iT邦幫忙

0

[新手發問]親緣關係樹實作

小弟第一次在版上發問,如有違反規定請多多包涵。

各位前輩好,小弟是一名仍在往前端努力中的學生。最近由於學校的專案需要實作出親緣關係樹之動畫,雖然能夠用SVG硬刻,但當資料量一大時就會產生畫也畫不完的SVG QQ,所以想來版上問問有沒有其他適合的方式或能夠提供小弟一個方向去研究。
首先我先說明一下大概的功能 :
1.
one.jpeg
上方為一個生物,放入一個特徵的示意圖,放入後會向下拉出一條線條。
2.
two.jpeg
以上為兩個生物,放入同一個特徵(一種顏色 = 一特徵),會向下聚合出一個Y字型動畫,目前是以SVG畫線加上一個隱藏的block的translate動畫實現。
3.
three.jpeg
最後是三個生物配合上兩個特徵的圖示,由於三個生物都具有藍色特徵,故藍色特徵層級較綠色高,將以更粗的線條放在第二層,動畫移動方式如圖示。

以上三點,小弟目前都是使用SVG配上block的隱藏出現硬刻(因為目前也只會這種方法QQ),但一到生物數量&特徵達7.8種時,畫線會變得極其複雜且耗時,所以想請問版上各位大大,是否有更好的方式能夠實現此效果,如果有,希望能夠不吝指教。

最後,謝謝觀看的各位,小弟繼續去趕工了QQ

1 個回答

2
ccutmis
iT邦高手 8 級 ‧ 2019-09-19 21:05:20

原本想建議樓主用d3.js 後來看到anime.js官方提供的範例好像可以拿來改,
於是下列的範例產生了,不太確定這是否可以稱作親緣關係樹,提供您參考。

demo url:
http://www.web3d.url.tw/ITHELP/JS_20190919/

demo源碼:

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<script src="anime.min.js"></script>
<style>
*{margin:0;padding:0;}
body{background:#eee;}
.animals{
	height:100px;
	display: -webkit-flex;
	-webkit-align-items: center; 
	display: flex;
	align-items: center; 
	margin:auto;
}
#animal0,#animal1,#animal2{	
	text-align:center;
	-webkit-flex: 1;
	flex: 1;
	color:#333;font-family:Arial;
}
.animalColor span{display:inline-block;width:8px;height:8px;}
</style>
</head>
<body>
<div class="animals">
	<div id="animal0">
		<h1 class="animalName"></h1>
		<p class="animalColor"></p>
	</div>
	<div id="animal1">
		<h1 class="animalName"></h1>
		<p class="animalColor"></p>
	</div>
	<div id="animal2">
		<h1 class="animalName"></h1>
		<p class="animalColor"></p>
	</div>
</div>
<div class="line-drawing-demo"></div>
<script>
let animals=['Duck','Rabbit','Panda'];
let color_arr=['#F00','#0F0','#00F','#FF0','#F0F','#0FF','#A06','#B7A','#3C9','#D37'];
let color_meaning_arr=['AAA','BBB','CCC','DDD','EEE','FFF','GGG','HHH','III','JJJ'];
let relationship=[
[1,1,0],
[1,0,1],
[1,1,0],
[1,1,1],
[1,1,1],
[1,0,1],
[1,1,0],
[1,1,1],
[1,0,0],
[1,0,1]
];
console.log(relationship);

let animalColorStr=['','',''];
let svgStr='';
for(i=0;i<relationship.length;i++){
	svgStr+=
	`<svg viewBox="0 0 500 200" style="position:absolute;left:0px;top:100px;height:100vh-100px;">
		<g fill="none" fill-rule="evenodd" stroke="${color_arr[i]}" stroke-width="${(color_arr.length*4)-(i*4)}" class="lines${i}">`;
	if(relationship[i][0]==1){
		svgStr+=`<path d="
M83 0 
L83 65 
C 83 65, 80 72, 93 75 
L166 75 
L166 140 
C 166 140, 163 147, 177 150 
L250 150 
L250 200
" />`;
		animalColorStr[0]+=`<span style="background-color:${color_arr[i]};"></span>`;
	}
	if(relationship[i][1]==1){
		svgStr+=`<path d="
M250 0 
L250 65 
C 250 65, 253 77, 240 75 
L166 75 
L166 140 
C 166 140, 163 147, 177 150 
L250 150 
L250 200
" />`;
		animalColorStr[1]+=`<span style="background-color:${color_arr[i]};"></span>`;
	}
	if(relationship[i][2]==1){
		svgStr+=`<path d="
M417 0 
L417 140
C 417 140, 417 148, 407 150 
L250 150 
L250 200
" />`;
		animalColorStr[2]+=`<span style="background-color:${color_arr[i]};"></span>`;
	}
	svgStr+=`</g></svg>`;
}

for(i=0;i<animals.length;i++){
	document.querySelector('#animal'+i+' .animalName').innerHTML=animals[i];
	document.querySelector('#animal'+i+' .animalColor').innerHTML=animalColorStr[i];
}

//console.log(svgStr);
document.querySelector('.line-drawing-demo').innerHTML=svgStr;

for(ii=0;ii<relationship.length;ii++){
	anime({
	  targets: '.line-drawing-demo .lines'+(ii)+' path',
	  strokeDashoffset: [anime.setDashoffset, 0],
	  easing: 'easeInOutSine',
	  duration: 1500,
	  delay: ii*600,
	  direction: 'alternate',
	  loop: false
	});
}
</script>
</body>
</html>

若想了解更多anime.js能做的事,就要自己去官網文件庫挖掘了。
anime.js官網 https://animejs.com/

我要發表回答

立即登入回答