發“連線題”并沒什么難點,這里主要分享的是:實現過程中的一點點布局設計上的小心思。
想要的效果大體長這樣(如下圖所示):
乍一看似乎需要獲取每個元素的位置信息、計算連線的端點坐標,似乎很繁瑣,而且每次頁面尺寸變化時,都得重新計算。其實,事情可以比想象中簡單很多…
1.1 將連線題分為上中下三個區塊,其中:
1)上下區塊均使用flex(justify-content: space-around)
2)中間區塊為canvas,在style屬性中將width和height設置為100%
.row-1 { justify-content: space-around; }
.row-2 {
height: 0; flex-grow: 1;
canvas { width: 100%; height: 100%; }
}
.row-3 { justify-content: space-around; }
1.2 這樣設置以后,有幾點好處:
1)計算直線端點(元素中點)坐標就會變得很輕松,只需要排序百分比與canvas的內容寬度相乘即可。
let x1=(上方元素下標 * 2 + 1) / (上方元素總數 * 2) * canvas.width
let x2=(下方元素下標 * 2 + 1) / (下方元素總數 * 2) * canvas.width
// 連線上方端點坐標: (x1, 0)
// 連線下方端點坐標: (x2, canvas.height)
2)頁面resize時無需重新計算,頁面也不會亂。當然如果resize前后差異較大,可能連線粗細程度會不美觀。
經測,一般不重新繪制也問題不大;如果要求高的話,可以在resize時重新繪制一下。(下圖是第一張圖在網頁resize后的效果,線條經過拉伸變細了)
3)如果你連canvas的尺寸也懶得初始化,也是可以的,只不過效果會差些(線條有點模糊,粗細不美觀),Chrome中canvas默認內容尺寸是300*100,效果如下圖所示(截圖可能視覺效果不明顯):
線條繪制的相關代碼如下:
Html
<canvas ref="canvas" :width="cvsWidth" :height="cvsHeight"></canvas>
Js
文由ScriptEcho平臺提供技術支持
項目地址:傳送門
Cola.js是一個JavaScript庫,用于繪制交互式網絡圖。它廣泛應用于社交網絡、知識圖譜、生物網絡等領域,幫助用戶可視化和探索復雜的數據關系。
本代碼實現了使用Cola.js繪制網絡圖的基本功能,包括:
const loadStyle=(styleUrl)=> { ... }
const loadJavascript=(jsUrl)=> { ... }
使用loadStyle和loadJavascript函數異步加載必要的CSS和JavaScript文件。
d3.json(
'webcola/website/examples/graphdata/miserables.json',
function (error, graph) { ... }
)
使用d3.js讀取JSON格式的網絡圖數據,包括節點和連線信息。
var group=svg
.selectAll('.group')
.data(groups)
.enter()
.append('rect')
.classed('group', true)
...
var link=svg
.selectAll('.link')
.data(graph.links)
.enter()
.append('line')
.attr('class', 'link')
...
var node=svg
.selectAll('.node')
.data(graph.nodes)
.enter()
.append('circle')
.attr('class', 'node')
...
分別創建節點、連線和組的DOM元素,并綁定相關數據。
dcola
.nodes(graph.nodes)
.links(graph.links)
.groups(groups)
.jaccardLinkLengths(40, 0.7)
.avoidOverlaps(true)
.start(50, 0, 50)
配置力導向布局算法的參數,包括節點、連線、組信息,以及連線長度、避免重疊等約束。
dcola.on('tick', function () { ... })
注冊一個回調函數,在力導向布局算法迭代時觸發,實時更新節點、連線和組的位置。
通過開發這段代碼,我們掌握了使用Cola.js繪制交互式網絡圖的技巧。
經驗與收獲:
未來拓展與優化:
獲取更多Echos
本文由ScriptEcho平臺提供技術支持
項目地址:傳送門
微信搜索ScriptEcho了解更多
一篇我們學習了如何使用zTree對靜態數據進行綁定并顯示。但是實際運用中數據都是數據庫或者經過計算后得到的,所以這一次我們將上次的Demo改為動態綁定。
數據表如下,其中平pId為0的是根節點
上一次講過zTree的回調事件中可以有許多函數,那么我們就利用點擊節點的回調函數進行動態綁定。但是問題來了,首次加載時網頁上并沒有節點,那么我們如何實現點擊節點加載數據呢?思路是這樣的,首次加載時用ajax向后臺發送一個空請求,點擊節點時ajax發送點擊節點的id。后臺收到請求,將請求參數取出,傳入數據庫查詢方法,此時進行判斷,若參數為空說明是首次加載,則執行的sql語句是select * from demo where pId='0' 即取出根節點,然后返回,而參數不為空則說明是點擊節點發出的請求,此時sql語句是select * from demo where pId='"+id+"'" 即取出父節點是我們點擊節點的節點。
下面上代碼
額,先看效果圖吧
前臺
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="css/metroStyle.css" type="text/css">
<script type="text/javascript" src="js/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="js/jquery.ztree.core.js"></script>
</head>
<body align="center" >
<div id="demotree" style="margin-left:230px;margin-top:50px">
<ul id="treeDemo" class="ztree"></ul>
</div>
</body>
<script type="text/javascript">
var treeNodes;
var setting={
//外觀
view: {
showIcon: true, //設置是否顯示節點圖標
showLine: true, //設置是否顯示節點與節點之間的連線
showTitle: true, //設置是否顯示節點的title提示信息
fontCss : {color:"black",size:30}
},
//異步
async:{
enable: true,//true代表異步
url: "/Demo/DataProcessing",//異步獲取數據的地址
autoParam: ["id=id"]//傳遞id
},
//數據類型
data: {
simpleData: {
enable: true, //設置是否啟用簡單數據格式(json格式)
idKey: "id", //設置啟用簡單數據格式時id對應的屬性名稱(對應json數據中的key)
pidKey: "pId" //設置啟用簡單數據格式時parentId對應的屬性名稱,ztree根據id及pid層級關系構建樹結構
}
},
//回調事件
callback: {
//點擊節點事件
onClick: function(event, treeId, treeNode, clickFlag) {
// 判斷是否父節點 ,是父節點則ajax向后臺發送節點名稱以獲取子文件
if(treeNode.isParent){
//判斷節點是否折疊,若已折疊則請求子節點的數據,返回后展開
if(treeNode.collapse==true){
//ajax提交請求
$.ajax({
url: "/Demo/DataProcessing",//請求的action路徑
type:"post", //提交方式
async:false,//同步
dataType:"json",//數據格式是json
data:{'id':treeNode.id}, //傳遞被點擊節點的id
error: function(){//請求失敗后執行的事件
},
//請求成功后執行事件
success:function(data)
{
var jsondata=data;
//json為空說明沒有子節點,不用執行操作
if(jsondata==null || jsondata==""){ }
//否則子節點添加到父節點
else{
var treeObj=$.fn.zTree.getZTreeObj("demotree");
var parentZNode=treeObj.getNodeByParam("name",treeNode.name, null);//獲取指定父節點
newNode=treeObj.addNodes(parentZNode,jsondata, false);
}
}
});
}
}
}
}
};
//首次加載用ajax請求初始化
$(function(){
$.ajax({
async : false,
cache:false,
type: 'POST',
dataType : "json",
url: "/Demo/DataProcessing",//請求的action路徑
error: function () {//請求失敗處理函數
alert('請求失敗');
},
success:function(data){ //請求成功后處理函數。
treeNodes=data; //把后臺封裝好的簡單Json格式賦給treeNodes
}
});
});
var zTree;
$(document).ready(function(){
$.fn.zTree.init($("#treeDemo"), setting, treeNodes);
});
</script>
</html>
后臺servlet
package myServlet;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import Db.DbOperate;
import Model.Demo;
import com.alibaba.fastjson.JSON;
/**
* Servlet implementation class DataProcessing
*/
@WebServlet("/DataProcessing")
public class DataProcessing extends HttpServlet {
private static final long serialVersionUID=1L;
/**
* @see HttpServlet#HttpServlet()
*/
public DataProcessing() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
String id=request.getParameter("id");
List<Demo> list;
try {
list=new DbOperate().getDemo(id);
String jsonArr=JSON.toJSONString(list);
System.out.println(jsonArr);
//response.setContentType("application/json; charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.getWriter().print(jsonArr);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
數據庫查詢
package Db;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import Model.Demo;
public class DbOperate {
private static String url="jdbc:mysql://localhost:3306/dir?rewriteBatchedStatements=true";
private static String user="root";
private static String password="";
public List<Demo> getDemo(String id) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
System.out.print("!!!!!!!!!");
Connection conn=DriverManager.getConnection(url, user, password);
List<Demo> list=new ArrayList<Demo>();
Statement s=null;
String sql;
if(id==null||id==""){
sql="select * from demo where pId='0'";
}
else{
sql="select * from demo where pId='"+id+"'";
}
s=conn.createStatement();
ResultSet rs=s.executeQuery(sql);
while (rs.next()) {
list.add(new Demo(rs.getString("id"), rs.getString("name"), rs.getString("pId"), rs.getInt("isParent")));
}
if (s !=null) {
s.close();
}
if (conn !=null) {
conn.close();
}
return list;
}
}
實體類
package Model;
public class Demo {
private String id;
private String name;
private String pId;
private int isParent;
public Demo(String id, String name, String pId, int isParent) {
super();
this.id=id;
this.name=name;
this.pId=pId;
this.isParent=isParent;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id=id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public String getpId() {
return pId;
}
public void setpId(String pId) {
this.pId=pId;
}
public int getIsParent() {
return isParent;
}
public void setIsParent(int isParent) {
this.isParent=isParent;
}
}
源碼可以私信獲取,謝謝支持
*請認真填寫需求信息,我們會在24小時內與您取得聯系。