基於 HTML5 Canvas 的元素週期表的展示
前言
之前在網上看到別人寫的有關元素週期表的文章,深深的勾起了一波回憶,記憶裡初中時期背的“氫氦鋰鈹硼,碳氮氧氟氖,鈉鎂鋁矽磷,硫氯氬鉀鈣”、“養(氧)龜(矽)鋁鐵蓋(鈣),哪(鈉)家(鉀)沒(鎂)青(氫)菜(鈦)”,高中時期記的質量守恆、元素守恆、原子守恆、電子守恆,時間過的飛快,轉眼我們都已經這麼大了。
現在我用 HT 來實現它,HT 有 2D 拓撲和 3D 模型場景,兩種形式我都實現了,話不多說,先看效果圖。
介面展示
整個頁面由 HT UI 元件構成,使用 ht.ui.TabLayout 標籤頁佈局元件,進行 23D 介面的分別展示。
2D介面:整體是一個 ht.ui.SplitLayout 分割元件(左右分割),左邊使用 ht.ui.HTView 包裝了 GraphView 拓撲圖元件,右邊是一個 ht.ui.Form 表單元件。
3D介面:整體是一個 ht.ui.SplitLayout 分割元件(上下分割),上邊新增了 ht.ui.HBoxLayout 構成的按鈕組,下邊是使用 ht.ui.HTView 包裝了 Graph3dView 場景。
demo 地址:http://www.hightopo.com/demo/elementTable/index.html
2D 介面程式碼分析
拓撲圖元件
先來說左邊的拓撲圖元件,ht.graph.GraphView 是 HT 框架中 2D 功能最豐富的元件,具有基本圖形的呈現和編輯功能,拓撲節點連線及自動佈局功能,電力和電信等行業預定義物件,具有動畫渲染等特效, 因此其應用面很廣泛,可作為監控領域的繪圖工具和人機介面,可作為一般性的圖形化編輯工具,可擴充套件成工作流和組織圖等企業應用。
拓撲圖中展示的 118 個元素,每一個都是 ht.Node 拓撲節點,預設的節點展示是一個小電腦樣式,在這裡我們通過 setImage 設定節點顯示的圖片資訊,如下圖:
向量圖通過點、線和多邊形來描述圖形,因此在無限放大和縮小圖片的情況下依然能保持一致的精確度。上圖就是一張向量圖,由 1 個矩形和 6 個文字組成,任意縮放不失真,大家可以訪問 demo 地址,通過滾輪來縮放拓撲圖進行體驗,具體向量圖的繪製請參考向量手冊。
肯定有人會有疑問,118 種元素,是否要繪製 118 張向量圖,感覺稍微還能接受,如果是成千上萬呢,那麼人會累趴下的。不用怕,HT 幫我們解決了這個問題,對繪製的向量圖進行資料繫結,將繪製內容的屬性繫結到節點的屬性上,應用中通過更新節點對應屬性,圖形介面就會自動重新整理,達到實時顯示資料的效果,比如我的這張向量圖,我將 6 個元素屬性文字內容和字型顏色以及矩形背景色都進行了資料繫結,繫結好之後我只需要通過 node.a('background', '#FEB64D') 就可以修改矩形的背景色(backgrouond 是矩形背景色繫結的屬性),具體資料繫結請參考資料繫結手冊。
既然說到了資料繫結,我們就先看下顯示元素分類的功能,如下圖對比,節點樣式的變化不是通過重新 setImage 設定另一張向量圖,而是修改原向量中繫結的樣式屬性。根據元素所屬類別,修改向量圖的矩形背景色、元素中文名文字顏色。切換狀態的按鈕是 ht.ui.ToggleButton 開關按鈕,擁有“0/1”兩種狀態的切換,通過監聽按鈕是否選中,來切換元素週期表樣式。
1 toggle.on('p:selected', e => {
2 if (e.newValue) {
3 this.htView.legend.s('2d.visible', true); // 顯示類別圖例
4 this.htView.addClassification(); // 展示分類
5 }
6 else {
7 this.htView.legend.s('2d.visible', false); // 隱藏類別圖例
8 this.htView.initElements(); // 原始樣式
9 }
10 });
元素類別圖例也是一個 ht.Node 節點,同樣是繪製的向量,它從一開始就在圖紙中, node.s('2d.visible', false) 設定為不可見,要展示分類時,再設定為 true 顯示。
表單皮膚
右邊的表單皮膚有 6 行,第 2 行為元素週期表展示和輪播展示的單選按鈕,來切換展示效果。
第 3 行就是上邊提到的顯示分類功能,第 4 行是一個文字輸入框,用來獲取元素序數,限制了只能輸入數字,還增加了輸入數的驗證,只能輸入 1~118 。
程式碼如下:
1 let textField = new ht.ui.TextField();
2 textField.setFormDataName('textField'); // 設定在表單中的名稱
3 textField.setPlaceholder('請輸入查詢的元素序數!');
4 textField.setMaskRe(/\d/); // 限制只能輸入數字
5 textField.setInstant(true); // 開啟即時模式,值改變就派發屬性改變事件
6 textField.on('p:value', (e) => { // 監聽值改變事件
7 let value = e.newValue;
8 if (value > 118) {
9 textField.setErrorMessage('只有 1 ~ 118 號元素喲!', {
10 placements: ['top']
11 });
12 }
13 else { textField.setErrorMessage(null); }
14 });
第 5 行是一個文字區域 ht.ui.TextArea,用來展示查詢的元素資訊。
第 6 行是一組按鈕,用來提交查詢資料和重置表單資訊。
3D 介面程式碼分析
按鈕組
上邊是一個 ht.ui.HBoxLayout 橫向佈局器,hbox 中新增了 4 個按鈕,來進行 3D 形態轉換。
按鈕支援圖示和文字,提供 normal、hover、active、disabled 四種狀態,按鈕生成程式碼:
1 createButton(text) {
2 let button = new ht.ui.Button();
3 button.setBorder(null);
4 button.setHoverBorder(null);
5 button.setActiveBorder(null);
6 button.setBackground(new ht.ui.drawable.ColorDrawable('rgba(37,115,194,0.6)', 4)); // normal 背景
7 button.setHoverBackground(new ht.ui.drawable.ColorDrawable('rgba(10,92,173,0.50)', 4)); // hover 背景
8 button.setActiveBackground(new ht.ui.drawable.ColorDrawable('rgba(15,132,250,0.6)', 4)); // active 背景
9 button.setText(text);
10 button.setTextColor('rgb(0, 211, 255)');
11 button.setHoverTextColor('rgb(0, 211, 255)');
12 button.setActiveTextColor('rgb(0, 211, 255)');
13
14 return button;
15 }
通過 button.on('click', e => { // 切換函式 }) 來監聽點選事件。
3D 場景
下邊是 ht.graph3d.Graph3dView,通過對 WebGL 底層技術的封裝,與 HT 其他元件一樣, 基於 HT 統一的 DataModel 資料模型來驅動圖形顯示,極大降低了 3D 圖形技術開發的門檻,在熟悉 HT 資料模型基礎上, 一般程式設計師只需要 1 個小時的學習即可上手 3D 圖形開發。
元素在 3D 場景顯示為一個面片,對面片進行 2D 時做好的向量貼圖,同樣通過修改節點屬性,來控制顯示樣式。
1 node.s({
2 'shape3d': 'billboard', // 設定節點型別為‘billboard’公告板
3 'shape3d.image': 'symbols/元素2.json', // 設定面片貼圖
4 'shape3d.reverse.flip': true, // 設定反面是否顯示正面內容
5 'shape3d.image.cache': true, // 進行貼圖快取
6 'shape3d.fixSizeOnScreen': false, // 設定是否固定保持螢幕大小,不隨縮放而變化
7 'select.brightness': 1 // 設定選中亮度為 1
8 });
接下來說幾種旋轉變化,dm 是 DataModel 即繫結的資料容器,datasMap 用來存放元素變化前後的位置資訊,用於動畫驅動時使用。
1. 隨機打亂:設定一組空間範圍值,生成範圍內的(x,y,z)隨機值,用以設定節點位置。
1 let dm = this.dm,
2 datasMap = {};
3
4 dm.each(data => {
5 let x = Math.random() * 2000 - 1000; // 獲取隨機 x
6 let y = Math.random() * 2000 - 1000; // 獲取隨機 y
7 let z = Math.random() * 500 - 250; // 獲取隨機 z
8
9 let position = data.getPosition3d(),
10 px = position[0],
11 py = position[1],
12 pz = position[2];
13
14 datasMap[data] = {
15 x: x,
16 y: y,
17 z: z,
18 px: px,
19 py: py,
20 pz: pz
21 };
22 });
2. 球形環繞:先計算求得球系座標,再根據規則轉化為空間直角座標。
1 let dm = this.elements,
2 datasMap = {};
3
4 let r = 500,
5 phi, theta;
6
7 for (let i = 0; i < 118; i++) {
8 let data = dm.get(117 - i);
9 phi = Math.acos(-1 + (2 * i ) / 118);
10 theta = Math.sqrt(118 * Math.PI) * phi;
11
12 let z = r * Math.sin(phi) * Math.cos(theta),
13 x = r * Math.sin(phi) * Math.sin(theta),
14 y = r * Math.cos(phi);
15
16 let position = data.getPosition3d(),
17 px = position[0],
18 py = position[1],
19 pz = position[2];
20
21 datasMap[data] = {
22 x: x,
23 y: y,
24 z: z,
25 px: px,
26 py: py,
27 pz: pz
28 };
29 }
3. 環形圍繞:設定一個環繞半徑、起始高度,以固定角度旋轉,每次降低節點的設定高度。
1 let dm = this.dm,
2 datasMap = {},
3 datas = dm.getDatas(),
4 radius = 400,
5 angle = 18,
6 num = 360 / angle;
7
8 let y = 300,
9 count = 0;
10 for (let i = 0; i < 6; i++) {
11 for (let j = 0; j < num; j++) {
12 let data = datas.get(count),
13 radian = Math.PI / 180 * j * angle;
14
15 if (!data) break;
16 count++;
17
18 let x = radius * Math.cos(radian),
19 z = radius * Math.sin(radian);
20
21 let position = data.p3(),
22 px = position[0],
23 py = position[1],
24 pz = position[2];
25
26 datasMap[data] = {
27 x: x,
28 y: y,
29 z: z,
30 px: px,
31 py: py,
32 pz: pz
33 };
34 y -= 6;
35 }
36 }
4. 復原:根據記錄的元素的行數和列數,計算元素節點的 xy 值,z 值固定。
1 let dm = this.dm,
2 datasMap = {};
3
4 dm.each(data => {
5 let index = data.a('index'),
6 row = data.a('row'),
7 col = data.a('col');
8
9 let position = data.getPosition3d(),
10 px = position[0],
11 py = position[1],
12 pz = position[2];
13
14 datasMap[data] = {
15 index: index,
16 row: row,
17 col: col,
18 px: px,
19 py: py,
20 pz: pz
21 };
22 });
最後有一個元素樣式的切換,右上角是一個 ht.ui.HBoxLayout 橫向佈局器,新增了 3 個 ht.ui.Label 子元件,通過限制 hbox 的寬度和 label 的寬度一致來達到現在的效果,通過監聽滾輪事件下的 label 來改變樣式。
總結
再次看過元素週期表,你是否想起化學課上滿黑板的化學方程式,是否想起了化學實驗課酒精燈的燃燒,是否還記得實驗操作流程、儀器的正確擺放。
再來操作一次吧:http://www.hightopo.com/demo/chemistry/index.html
相關文章
- 基於 HTML5 Canvas 的元素週期表展示HTMLCanvas
- 基於three.js的3D炫酷元素週期表JS3D
- 基於 Canvas 的 HTML5 文字動畫特效CanvasHTML動畫特效
- 基於 HTML5 Canvas 的樓宇自控系統HTMLCanvas
- 元素週期表動態桌面桌布
- 基於 HTML5 Canvas 的拓撲元件 ToolTip 應用HTMLCanvas元件
- 基於 HTML5 Canvas 的可互動旋鈕元件HTMLCanvas元件
- 基於 HTML5 Canvas 實現的文字動畫特效HTMLCanvas動畫特效
- 基於 Canvas 的 HTML5 互動式地鐵線路圖CanvasHTML
- 基於 HTML5 Canvas 的工控機櫃 U 位動態管理HTMLCanvas
- 基於 HTML5 Canvas 的 3D 熱力雲圖效果HTMLCanvas3D
- 基於 Canvas 的 HTML5 工控機櫃 U 位動態管理CanvasHTML
- 基於 HTML5 + WebGL 的太陽系 3D 展示系統HTMLWeb3D
- 基於 HTML5 Canvas 實現文字動畫特效HTMLCanvas動畫特效
- 基於 HTML5 Canvas 的電信機櫃 U 位動態管理HTMLCanvas
- 基於 HTML5 Canvas 電信網路拓撲圖的快速搭建HTMLCanvas
- html5中canvas元素建立畫布介紹HTMLCanvas
- 基於 HTML5 的 3D 工業網際網路展示方案HTML3D
- 基於 HTML5 的工業網際網路 3D 展示方案HTML3D
- 基於virtual dom 的canvas渲染Canvas
- 基於canvas的骨骼動畫Canvas動畫
- HTML5的SVG和Canvas的使用HTMLSVGCanvas
- 基於 HTML5 Canvas 實現的 TP-LINK 電信拓撲裝置皮膚HTMLCanvas
- 基於 HTML5 Canvas 的 3D 渲染引擎構建生產管控系統HTMLCanvas3D
- [Java基礎]物件的生命週期Java物件
- 基於canvas實現的高效能、跨平臺的股票圖表庫--clchartCanvas
- 元素週期表應加上氧化態?機器學習破解晶體結構的氧化態機器學習
- 基於三維地籍的全生命週期“一碼管地”
- Html5 Canvas動畫基礎(碰撞檢測)HTMLCanvas動畫
- HTML5學習之Canvas基礎知識HTMLCanvas
- 基於 HTML5 WebGL 的智慧城市(一)HTMLWeb
- 基於Flutter Canvas的飛機大戰(一)FlutterCanvas
- 基於Flutter Canvas的飛機大戰(二)FlutterCanvas
- 用HTML5的canvas畫太陽系HTMLCanvas
- 基於 HTML5 Canvas 2D 拓撲圖和 3D 機櫃模型的增刪操作HTMLCanvas3D模型
- 整個元素週期表通用,AI 即時預測材料結構與特性AI
- 基於HTML5的移動Web應用HTMLWeb
- 關於Spring生命週期控制的介面:SmartLifecycleSpring