緣起:
前陣子有好長的一段時間都在弄 amchart 5 的 ForceDirected
圖表,為了就是要產生快速查詢的圖表
弄了好幾個禮拜才完成,中間碰上不少問題,但大部份的需求都是多看看它們的 API、然後設定某個屬性就能達成了。唯有一個需求,它很麻煩,不是設個屬性就能解決的,而且 API 裡面根本也沒有相對應的設定可以控制,最後,我是用 JavaScript 的 Proxy 來達成這個需求。
這次的季會,我需要上台報告,原本是想要分享之前前弄的
prismjs 美化 Blogger 裡面的
code,但後來協理跟我說,這個東西好像太簡單,而且好像在專案上的實用性也不高,請我換個主題,所以我才會開始寫這篇文章,想說,在這邊紀錄完後,再做
PPT 也會比較方便。
這篇先簡單介紹 ForceDirected
的使用,下篇再介紹碰到的問題跟解決方法。
ForceDirected 的基本:
我是直接抄它們網站的範例,先用盡量短的程式碼來生個圖表出來看看,我是開個 asp webform
的專案來寫程式,主要是為了在專案啟動 iis express,之後 amchart
在存取資料夾裡的圖片才不會碰上問題。
aspx 的頁面長這樣,要使用 amchart 的功能,需要引用它們的 js
函式庫,可以從它們提供的 CDN 來引用,或是下載下來在 local 端引用。index.js
是核心,必引用,再來是 Animated.js,圖表的動化效果,最後是
hierarchy.js,因為 ForceDirected 是屬於階層圖表。
再來是在表單裡加個 id=myAmchartDiv 的 div,到時 amchart
圖表要掛載在它上面,設定它的寬為 100%,長為 800px。我把產生圖表的 js
碼寫在專案 Scripts 資料夾裡的 js 檔中
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="birdshiu.aspx.cs" Inherits="ForceDirected.birdshiu" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title></title>
<script src="//cdn.amcharts.com/lib/5/index.js"></script>
<script src="//cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<script src="//cdn.amcharts.com/lib/5/hierarchy.js"></script>
<style type="text/css">
#myAmchartDiv{
width:100%;
height:800px;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<div id="myAmchartDiv"></div>
</div>
</form>
<script type="text/javascript" src="Scripts/index.js"></script>
</body>
</html>
以下為 index.js
document.addEventListener("DOMContentLoaded", function () {
let myAm5Root = am5.Root.new("myAmchartDiv"); //傳入 div 的 id
myAm5Root.setThemes([
am5themes_Animated.new(myAm5Root) //設定 root 的動畫效果,預設即可
]);
let myAm5Container = myAm5Root.container.children.push(//root 裡放入一個 container
am5.Container.new(myAm5Root, {
width: am5.percent(100),
height: am5.percent(100),
layout: myAm5Root.verticalLayout
})
);
let myAm5ForceDirected = myAm5Container.children.push( //container 裡面放入 ForceDirected 圖表
am5hierarchy.ForceDirected.new(myAm5Root, {
downDepth: 1,
initialDepth: 3, //初始展開層數
topDepth: 1,
valueField: "value",
categoryField: "name",
childDataField: "children"
})
);
//圖表資料 (物件陣列)
let myObjData = [{
name: "Root",
value: 0,
children: [{
name: "A0",
value: 100,
children: [{
name: "A0A1",
value: 80,
children: [{
name: "A0A0A2",
value: 71
}, {
name: "A0A0C2",
value: 48
}]
}, {
name: "A0B1",
value: 27
}, {
name: "A0C1",
value: 70,
children: [{
name: "A0C2A2",
value: 40
}, {
name: "A0C2B2",
value: 40,
children: [{
name: "A0C2B1A3",
value: 54
}]
}]
}, {
name: "A0D1",
value: 89
}]
}]
}];
myAm5ForceDirected.data.setAll(myObjData); //設定 ForceDirected 的資料
myAm5ForceDirected.set("selectedDataItem", myAm5ForceDirected.dataItems[0]);//採用第一個 Object
});
第 1 行 : amchart 一定要有個 root,new
裡面傳的是要被掛載的 div 的 id。
第 4 行 : 設定 root
的動畫效果,不用特別多做其它設定。
第 16 行 : 把 ForceDirected 圖表放進
Container 裡,ForceDirected 的屬性設定可以查看它的
API 文件,比較重要的是那三個 Field 有關的設定,它是用來指定
value、category、childData 是要參考 Object 資料的哪個 key。
第 27 行 : ForceDirected
的資料,它好像一定要是一個物件陣列,我們的範例只會用到一個物件而已。Root
必需要有,但真正會呈現為圖表的會是它的
children。整個物件資料的架構會跟樹一樣。
第 81 行 : 用 ForceDirected 的 data 的 setAll
可以設定圖表的資料來源。
第 82 行 : 用 set 方法來設定 ForceDirected 的
selectedDataItem,就是圖表目前要呈現的資料集。可以用 dataItems
來取得圖表的來源資料,因為是陣列資料,又只有一筆資料,所以取[0]。
最後呈現出來的圖表會長這樣
See the Pen Untitled by 鳥旭 (@lbdjszpl-the-lessful) on CodePen.
以上是一個 Amchart 5 ForceDirected 圖表的基本。
補充:
我想補充一些我在研究 Amchart5 時,最常使用到的功能
在新增一個元件時,通常都是寫這樣的語法,可以看上面
"ForceDirected 的基本" 程式的 8、16
行,如果加完新的元件後,想要再對它做操作的話,可以用個變數紀錄,它 push
成功後會回傳那個新加入的元件。
可以用 set 或 setAll 來設定元件的屬性,set
是設定單一屬性,傳入的是屬性名稱跟值,可以是字串、數字...,就看那個屬性接受的是什麼類型的資料。setAll
是可以一次設定多個屬性質,傳入的是 Object。在 API 文件中,只要是條列在
Settings 部份的屬性都能透過 set 與 setAll 來設定。
有些 class 會有 template 這個屬性可以存取,這邊舉
ForceDirected 的 nodes 來說,它是一個 ListTemplate,有點像 C# 的
List,是 Generic Type,這邊放的 class 是
LinkedHierarchyNode。如果我們想要設定那些 node 的屬性,雖然可以用
ListTemplate 的
each
來逐一設定每個 node,但其實直接用 template 去設定會更簡潔。
myAm5ForceDirected.nodes.template.set("draggable", false); //設定球球不能拖拉
設定完後,球球就不能被拖拉了
See the Pen ForceDirected-1 by 鳥旭 (@lbdjszpl-the-lessful) on CodePen.
再舉兩個例子,如果把 toggleKey 設定成 "none"
的話,點擊球球就不會打開跟收合。如果不想看到外層的圈圈的話,可以把
outerCircles 的 forceHidden 設成 true。
myAm5ForceDirected.nodes.template.set("toggleKey", "none");//設定球球不能點擊展開或收合
myAm5ForceDirected.outerCircles.template.set("forceHidden", true); //把外層的圓圈給藏起來
設定完後的結果
See the Pen ForceDirected-2 by 鳥旭 (@lbdjszpl-the-lessful) on CodePen.
以上。下一篇會接著講我碰到的困難以及如何用 Proxy 來解決
沒有留言:
張貼留言