基於 HTML5 WebGL 的 3D 網路拓撲圖
前言
在資料量很大的 2D 場景下,要找到具體的模型比較困難,並且只能顯示出模型的的某一部分,顯示也不夠直觀,這種時候能快速搭建出 3D 場景就有很大需求了。但是搭建 3D 應用場景又依賴於通過 3ds Max 或 Maya 的專業 3D 設計師來建模,Unity 3D 引擎做圖形渲染等,這對使用者來說都是挑戰!不過,HT 一站式的提供了從建模到渲染,包括和 2D 元件呈現和資料融合的一站式解決方案。HT 基於 WebGL 的 3D 技術的圖形元件 ht.graph3dView 元件通過對 WebGL 底層技術的封裝,與 HT 其他元件一樣, 基於 HT 統一的 DataModel 資料模型來驅動圖形顯示,極大降低了 3D 圖形技術開發的門檻,在熟悉HT 資料模型基礎上,一般程式設計師只需要 1 小時的學習即可上手 3D 圖形開發。
好了,廢話不多說,先附上 Demo:http://www.hightopo.com/demo/blog_3dedge_20170630/index.html
當然,這裡的我只是用簡單的圖形來表示裝置,腦洞大開的你當然可以將其換成更有意思的模型。
3D 場景的搭建
1、準備工作:
3D 和 2D 的 API 的設計上保持了很多一致性,3D 檢視元件是 ht.graph3d.Graph3dView, 2D 檢視元件是 ht.graph.GraphView,兩者可共享同一資料模型 DataModel。在 HT 中,為了讓了獲得接近真實三維物體的視覺效果,我們通過透視投影使得遠的物件變小,近的物件變大,平行線會出現先交等更接近人眼觀察的視覺效果:
如上圖所示,透視投影最終顯示到螢幕上的內容只有截頭椎體部分的內容,因此 GraphView 提供了 eye,center,up,far,near, fovy 和 aspect 引數來控制截頭椎體的具體範圍,我們在實際運用中用到更多的是 eye 和 center:
-
getEye() | setEye([x, y, z]),決定眼睛(或 Camera)所在位置,預設值為 [0, 300, 1000];
-
getCenter() | setCenter([x, y, z]),決定目標中心點(或 Target)所在位置,預設值為 [0, 0, 0];
詳情看 HT for Web 3D 手冊。
dataModel = new ht.DataModel();
g3d = new ht.graph3d.Graph3dView(dataModel);
g3d.setEye(1800, 800, 1000);
g3d.setCenter(0, 100, 0);
g3d.setDashDisabled(false);
g3d.getView().style.background = 'rgb(10, 20, 36)';
g3d.addToDOM();
2、建立裝置:
伺服器,Demo 中的伺服器其實是通過 addStyleIcon 方式在伺服器的位置新增圖片,詳情可看 HT for Web 入門手冊:
//註冊圖片
ht.Default.setImage('server', 'server.png');
var server = new ht.Node();
server.s3(0, 0, 0);
server.p3(0, 60, 0);
server.addStyleIcon('icon', {
position: 0,
width: 200,
autorotate: true,
transparent: true,
height: 200,
names: ['server']
});
dataModel.add(server);
工作臺,這裡的工作臺實際上是立體圓柱來表示的,HT 在 GraphView 的 2D 圖形上,呈現各種圖形是通過 style 的shape 屬性決定,類似的 HT 在 3D 上提供了 shape3d屬性,預定義了多種 3D 的形體,詳情見 HT for Web 3D 手冊。不過在這裡我並沒有用預定義的圖形,而是通過 ht.Default.createRingModel 的方式建立圓柱,該方法可以根據 xy 平面的曲線,環繞一週形成 3D 模型,所以可以用來定義多種圓形 3D 模型。
var desktop = new ht.Node();
desktop.s({
'3d.selectable': false,
'shape3d': ht.Default.createRingModel([
0, 40,
450, 40,
450, 0,
0, 40
], null, 20, false, false, 50),
'shape3d.color': '#003333'
});
desktop.s3(1, 1, 1);
dataModel.add(desktop);
平臺上的裝置,我們一共建立了 32 個裝置:
var count = 32;
radius = 400;
index = count/2;
for (var i = 1; i <= count/2; i++) {
var device1_angle1 = Math.PI * 2 * (index - i) / count,
device1_angle2 = Math.PI * 2 * (index + i) / count,
device1_angle3 = Math.PI * 2 * index / count;
var device1_1 = createDevice(device1_angle1, radius, 60),
device1_2 = createDevice(device1_angle2, radius, 60),
device1_3 = createDevice(device1_angle3, radius, 60);
layoutDevice1(device1_1, device1_angle1);
var device1_edge1 = createEdge(device1_1, server, 'line1');
device1_edge1.s({'shape3d.color': 'rgb(205, 211, 34)'});
dataModel.add(device1_1);
dataModel.add(device1_edge1);
layoutDevice1(device1_2, device1_angle2);
var device1_edge2 = createEdge(device1_2, server, 'line1');
device1_edge2.s({'shape3d.color': 'rgb(205, 211, 34)'});
dataModel.add(device1_2);
dataModel.add(device1_edge2);
layoutDevice1(device1_3, device1_angle3);
var device1_edge3 = createEdge(device1_3, server, 'line1');
device1_edge3.s({'shape3d.color': 'rgb(205, 211, 34)'});
dataModel.add(device1_3);
dataModel.add(device1_edge3);
}
為了讓建立的裝置在平臺上的佈局更加合理,根據 index 計算出裝置擺放角度,並且根據圓柱中心,圓盤半徑和角度計算出每個裝置擺放的位置:
function createDevice (angle, x, y) {
var node = new ht.Node();
cos = Math.cos(angle);
sin = Math.sin(angle);
node.p3(x*sin, y, x*cos);
return node;
}
其他裝置,
var num = 18;
var h = [800, 900, 1000, 1100, 1200];
var v = [40, 60, 80, 100];
var colors = ['#fcfc63', '#00E1E4'];
for (var j = 0; j < num; j++) {
var device2_angle = Math.PI * j / num;
var device2 = createDevice(device2_angle, h[Math.floor(Math.random()*5)], v[Math.floor(Math.random()*4)]);
device2.s3(100, 20, 100);
device2.s({
'shape3d': 'cylinder',
'shape3d.color': colors[Math.floor(Math.random()*2)]
});
var device2_edge = createEdge(device2, desktop , 'line2');
device2_edge.s({'shape3d.color': 'rgb(0, 203, 94)'});
dataModel.add(device2);
dataModel.add(device2_edge);
}
3、連線
HT for Web 提供了預設的直線和多點的連線型別能滿足大部分基本拓撲圖形應用,但在這裡我們需要根據實際需求繪製曲線,所以,需要用到自定義連線型別,詳情看 HT for Web 連線型別手冊:
用 ht.Default.setEdgeType(type, func, mutual) 函式可用於自定義新連線型別:
-
type:字串型別的連線型別,對應 style 的 edge.type 屬性;
-
func:函式型別,根據傳入引數(edge,gap,graphView,sameSourceWithFirstEdge)返回連線走向資訊
1、edge:當前連線物件;
2、gap:多條連線成捆時,本連線物件對應中心連線的間距;
3、graphView:當前對應拓撲元件物件;
4、 sameSourceWithFirstEdge:boolean 型別,改連線是否與同組的第一條同源;
5、返回值為 {points: new ht.List(…),segments:new ht.List(…)} 結構的連線走向資訊,segments 可取值如下:
1)、moveTo,佔用 1 個點資訊;
2)、lineTo,佔用 1 個點資訊;
3)、quadraticCurveTo,佔用 2 個點資訊;
4)、bezierCurveTo,佔用 3 個點資訊;
5)、closePath,不佔用點資訊;
- mutual:該引數決定連線是否影響起始或結束節點上的所有連線,預設為 false 代表隻影響同 source 和 target 的 EdgeGroup 中的連線,HT 預定義的連線型別中,字尾為 2 的型別都是 mutural 為 true 的複雜連線型別。
在 Demo 中定義了兩種型別的連線,分別為 line1 和 line:
ht.Default.setEdgeType('line1', function(edge){
var sourcePoint1 = edge.getSourceAgent().getPosition(),
targetPoint1 = edge.getTargetAgent().getPosition(),
points1 = new ht.List();
points1.add(sourcePoint1);
points1.add({
x: (sourcePoint1.x + targetPoint1.x)/2 + 200,
e: sourcePoint1.e,
y: (sourcePoint1.y + targetPoint1.y)/2
});
points1.add(targetPoint1);
return {
points: points1,
segments: new ht.List([1, 3])
};
});
ht.Default.setEdgeType('line2', function(edge){
var sourcePoint = edge.getSourceAgent().getPosition(),
targetPoint = edge.getTargetAgent().getPosition(),
points = new ht.List();
points.add(sourcePoint);
points.add({
x: (sourcePoint.x + targetPoint.x)/2,
e: ((sourcePoint.e + targetPoint.e)/2 || 0) - 300,
y: (sourcePoint.y + targetPoint.y)/2
});
points.add({
x: targetPoint.x,
e: targetPoint.e -80,
y: targetPoint.y
});
return {
points: points,
segments: new ht.List([1, 3])
};
});
連線型別定義好,接下來就是建立連線,但是連線上還有流動效果,這個又怎麼實現呢?我們 HT 有擴充套件流動線外掛,可以在 ht.Shape 和 ht.Edge 上增加流動效果,支援內部流動元素或使用者自定義的流動元素沿著路徑步進,要使用也非常方便,只需要引入 ht-flow.js 檔案,詳情可見 HT for Web 流動線手冊,但是外掛並不適用於 3D 模型中,那在 3D 模型中該怎麼辦呢?即使不能使用現成的外掛,我們也可以實現流動效果,可以看 HT for Web 入門手冊 中連線部分,我們可以將連線樣式通過 edge.dash 設定為虛線後,動態改變 edge.dash.offset 虛線偏移,即可實現流動效果,所以,我們建立連線時:
function createEdge (source, target , type) {
var edge = new ht.Edge(source, target);
edge.s({
'edge.color': 'yellow',
'edge.dash': true,
'edge.dash.3d': true,
'edge.dash.width': 4,
'edge.type': type,
'edge.dash.color': 'rgb(10, 20, 36)',
'edge.dash.pattern': [20, 25]
});
edge.a({
'flow.enabled': true,
'flow.direction': -1,
'flow.step': 4
});
return edge;
}
最後,要讓虛線流動起來,可以使用 HT 中的排程,詳情可看 HT for Web 排程手冊:
flowTask = {
interval: 50,
action: function(data){
if(data.a('flow.enabled')){
var offset = data.s('edge.dash.offset') + data.a('flow.step') * data.a('flow.direction');
data.s('edge.dash.offset', offset);
}
}
};
dataModel.addScheduleTask(flowTask);
到這裡,Demo 中的主要技術點都已經介紹了一遍,可以看出我們 HT 的強大之處,當然我們官網上還有很多很有意思的效果,大家也可以看一看,也可以玩一玩我們的 HT 感受它的強大之處,再次附上 Demo 地址: http://www.hightopo.com/demo/blog_3dedge_20170630/index.html。
相關文章
- 基於 WebGL 的 HTML5 3D 網路拓撲圖WebHTML3D
- 基於 WebGL 的 HTML5 網路拓撲結構 3D 圖WebHTML3D
- 基於 HTML5 Canvas 電信網路拓撲圖的快速搭建HTMLCanvas
- 基於HTML5 WebGL 將拓撲圖和圖表繪製在 3D 六面體上HTMLWeb3D
- 基於 HTML5 的網路拓撲圖之 DataBinding 資料繫結HTML
- 基於 HTML5 網路拓撲圖的快速開發之入門篇(一)HTML
- 基於 HTML5 網路拓撲圖的快速開發之入門篇(二)HTML
- 快速建立 HTML5 Canvas 電信網路拓撲圖HTMLCanvas
- 網路拓撲圖:網路拓撲圖介紹及線上製作
- 快速開發基於 HTML5 網路拓撲圖應用之 DataBinding 資料繫結篇HTML
- 基於 HTML5 Canvas 2D 拓撲圖和 3D 機櫃模型的增刪操作HTMLCanvas3D模型
- 基於 HTML5 WebGL 的 3D 機房HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 挖掘機HTMLWeb3D
- 基於 HTML5 Canvas 的拓撲元件 ToolTip 應用HTMLCanvas元件
- 基於 HTML5 的 WebGL 3D 隧道監控HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 科幻風機HTMLWeb3D
- 基於 WebGL 的 3D Chart 圖表Web3D
- 基於 HTML5 WebGL 的 3D 風機 Web 組態工業網際網路應用HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 工控裙房系統HTMLWeb3D
- 基於 HTML5 WebGL 的 3D 模型斜面生成HTMLWeb3D模型
- 基於 WebGL HTML5 的 3D 模型分離控制WebHTML3D模型
- 基於 WebGL 的 HTML5 3D 工控裙房系統WebHTML3D
- 基於d3.js的關係拓撲圖JS
- 基於 WebGl HTML5 的 3D 視覺化機房WebHTML3D視覺化
- 基於 HTML5 + WebGL 的 3D 風力發電場HTMLWeb3D
- 基於 WebGL 的 HTML5 3D SCADA 主站系統WebHTML3D
- 網路拓撲結構
- 商企網路拓撲的搭建
- 基於 HTML5 結合網際網路+ 的 3D 隧道HTML3D
- 基於 HTML5 WebGL 的 3D 棉花加工監控系統HTMLWeb3D
- 基於 HTML5 + WebGL 的太陽系 3D 展示系統HTMLWeb3D
- 基於 WebGL 實現的 HTML5 3D “彈力”佈局WebHTML3D
- 基於 HTML5 WebGL 實現的 3D “彈力”佈局HTMLWeb3D
- 基於 WebGL 的 HTML5 3D 棉花加工監控系統WebHTML3D
- 基於 HTML5 的結合網際網路+ 的 3D 隧道HTML3D
- 基於 HTML5 WebGL 的 3D 場景中的燈光效果HTMLWeb3D
- 基於 HTML5 WebGL 構建智慧城市 3D 場景HTMLWeb3D
- 基於 HTML5 的 3D 工業網際網路展示方案HTML3D