基於HTML5和WebGL的三維可視立體動態流程圖

慣例先扯點閒篇

記得15年那會兒,我給人講WebGL,還得從頭科普,三令五申要用Chrome,末了再強調一句,記得啓用WebGL功能。今天,但凡懂點兒Web開發的,都會來一句「網頁3D用WebGL」。數據庫

怎麼形容這種感覺呢?canvas

圖片描述

這兩年的技術發展,你們想必都看在眼裏,單用「爆發」二字,實在難以描述其中的驚天鉅變。而回到網頁3D這個話題上,我想,最大的驅動力,莫過於16年至今虛擬現實的迅速崛起,完全推動了三維可視化技術的日新月異,而物聯網發力,又開啓了一扇通往新世界的大門。後端

遊戲界至今爭論不休的Unity仍是HTML5,依我看至少WebGL活的好好的,而插件技術麼,則讓我想起了一首悲傷的歌:dying in the sun…數組

三維可視化應用盤點

今天固然仍是給你們介紹一款最新的三維可視化成果,開始正題前,我想先盤點一下這兩年還算靠譜的一些三維應用。架構

工業上的,偏銷售側有複雜零件的三維展現,依託零件原有模型,作好參數轉換,比較容易實現。偏管理側,主要是廠房車間和生產設備的三維監控;電力行業,有無人值守變電站的巡檢和監控,結合三維能夠進行遠程巡檢做業,下降人工做業的風險;倉庫和糧倉,引入三維後,能夠結合庫房系統、環境系統,進行全方位的管理;礦山和隧道,這個很好理解:做業越是危險、對環境要求越高的地方,越是須要虛擬仿真;3D家裝設計, 一般是在線模式,拖拽設計,結合傢俱販售,早先是以Stage3D爲主,這兩年也看到不少WebGL的案例;博物館、圖書館、檔案館的導覽結合解說,複雜設備的虛擬仿真培訓商品展現,這個比較多了,像虛擬試衣間,商品的三維在線瀏覽,好比剛看到這款霸氣側漏的零食:框架

圖片描述

開個玩笑。其實無論哪一個行業,三維應用很大的一部分工做量源於建模,而此次咱們想分享的是和上述應用徹底不一樣的一個案例。函數

正文

此次的案例,對模型幾乎沒有要求,只是用了最基本的形狀元素,可是卻能夠解決企業在不斷髮展壯大,尤爲是信息化進程不斷深刻的過程當中,都會遇到的問題,那就是如何將複雜流程可視化優化

什麼是流程?

流程,看起來很簡答的兩個字,英文process。咱們這裏所說的流程,主要是企業的業務流程,如生產流程、各種行政申請流程、財務審批流程、人事處理流程、質量控制及客服流程等等。動畫

業務流程對於企業的意義不只僅在於對企業關鍵業務的一種描述;更在於對企業的業務運營有着指導意義,這種意義體如今對資源的優化、對企業組織機構的優化以及對管理制度的一系列改變。這種優化的目的實際也是企業所追求的目標:下降企業的運營成本,提升對市場需求的響應速度,爭取企業利潤的最大化。(from智庫百科MBAlib)this

爲啥我忽然開始拽商業名詞了呢?由於,這是甲方爸爸給出的一個難題。

甲方爸爸的企業,部門繁多,流程複雜,爲了提高業務流程的效率,同時優化企業自身的管理,提出了一個將其現有業務流程進行三維可視化的需求。

爲何要把流程進行三維可視化呢?

通俗的說,由於平面的實在是看不清理不順了;時髦點講,只有「升維」,才能展現和包容更多的信息。

看到這裏的三體同好們,請不要吝嗇向我隔空揮舞小手!

圖片描述

舉個栗子

甲方爸爸的信息實在太多,並且不能透露,咱們就找其中幾個簡單的舉個例子,好比每一個企業天天都在處理的報帳流程:(應要求馬賽克了一些文字)

報帳流程業務圖:
圖片描述

二層邏輯交互圖:
圖片描述

報帳業務基礎架構:
圖片描述

看到如此複雜的結構,不管你是如下哪一種表情,都不要驚慌:
圖片描述圖片描述圖片描述

流程結構梳理

咱們先簡單梳理下流程圖的大體框架,一共能夠分爲五層:

  • 業務流程層:起點、審批、服務;
  • 應用邏輯層:WEB服務、數據庫服務、定時做業服務、接口服務、應用服務;
  • 實例:WEB服務實例、財輔數據庫實例、支付服務實例;
  • OS:EB服務OS、財輔數據庫OS;
  • 硬件:主機、交換機。

圖片描述

初稿

爲了讓這五層之間的關係一目瞭然,分層展現是必不可少的。每一個層次裏,又分爲幾個模塊,層次與層次、模塊與模塊之間都有業務上的聯繫。根據梳理的邏輯關係,我先整了一個初稿。流程和業務先用簡單的方塊和圓柱代替,底層的機櫃模型,直接用存貨模型,機房相關的模型,咱們大大的有。
圖片描述

雖然看起來層次感有了,不過這只是個總體的框架demo,咱們在這基礎上一步步修改。

圓弧效果

說下層模型的圓弧效果。爲了把每一個層作成圓弧的效果,我把層模型拆解成了由9個簡單模型組合而成,上圖給大家看(原諒我圖畫得渣渣)。
圖片描述

模型一、二、三、四、5均爲厚度相同的立方體,模型六、七、八、9爲大小相等的1/4圓柱體,9個模型組合成層模型。

模型1的代碼:(模型1,2,3,4,5差很少,就只貼模型1的代碼了。)

var centerNode = new mono.Cube({
    width: width,
    height: height,
    depth: depth,
});
centerNode.s({
    'm.type': 'phong',
    'm.color': color
});

模型6的代碼:

var leftTopCylinder = new mono.Cylinder({
    radiusTop: radius,
    radiusBottom: radius,
    height: height,
    arcLength: Math.PI / 2, //圓柱的圓弧所佔長度
    arcStart: Math.PI //圓弧開始的角度
});
    
leftTopCylinder.s({
    'm.type': 'phong',
    'm.color': color
});
leftTopCylinder.p(-width / 2, 0, -depth / 2);

9個模型合併:

var combo = new mono.ComboNode([centerNode, leftNode, rightNode, topNode, bottomNode, leftTopCylinder, rightTopCylinder, leftBottomCylinder, rightBottomCylinder],['+'],true);

背景和配色

首先,增長了背景圖片,選取的是一張星空的圖片,以後根據背景修改了配色和部分模型。
圖片描述

效果仍是不錯的,看起來更加大氣。增長背景代碼:

network.setClearColor(0, 0, 0);
network.setClearAlpha(0);
network.setBackgroundImage('./images/background.jpg');

文字

圖中顯示文字相似對話框的東西實際上是billboard,先建立一個billboard,再用canvas畫一張圖做爲貼圖貼到上面就能夠了。

var billboard = new mono.Billboard();
var canvas = document.createElement('canvas');
    var context = canvas.getContext('2d');
    context.font = "130px 微軟雅黑";

    var array = [];
    if (text.indexOf("\n")) {
        array = text.split("\n");
    } else {
        array = [text]
    }
    var length = 0;
    for (var i = 0; i < array.length; i++) {
        if (i == 0) {
            length = context.measureText(array[i]).width;
        } else {
            length = Math.max(context.measureText(array[i]).width, length);
        }
    }

    var size = mono.Utils.getMaxTextSize(array, context.font);
    var width = mono.Utils.nextPowerOfTwo(length);
    var oHeight = size.height;
    var arrowHeight = 40;
    var arrowWidth = 80;
    var height = mono.Utils.nextPowerOfTwo(oHeight + arrowHeight);

    canvas.height = height;
    canvas.width = width;
    var lineHeight =(height - arrowHeight - 40) / array.length;
    var oLineHeight = oHeight / array.length;
    var radius = width / 16;

    var context = canvas.getContext('2d');
    context.globalAlpha = 0.9;
    context.fillStyle = bgColor;
    context.save();
    context.beginPath();
    context.moveTo(radius + 10, 10);
    context.lineTo(width - radius - 10, 10);
    context.arcTo(width - 10, 10, width - 10, radius + 10, radius);
    context.lineTo(width - 10, height - arrowHeight - radius - 10);
    context.arcTo(width - 10, height - arrowHeight - 10, width - radius -10, height - arrowHeight - 10, radius);
    context.lineTo(width / 2 + arrowWidth / 2 - 10, height - arrowHeight - 10);
    context.lineTo(width / 2 - 10, height - 10);
    context.lineTo(width / 2 - arrowWidth / 2 - 10, height - arrowHeight - 10);
    context.lineTo(radius + 10, height - arrowHeight - 10);
    context.arcTo(10, height - arrowHeight - 10, 10, height - arrowHeight - radius - 10, radius);
    context.lineTo(10, radius + 10);
    context.arcTo(10, 10, radius + 10, 10, radius);
    context.closePath();
    context.fill();
    context.globalAlpha = 1;
    context.lineWidth = 10;
    context.strokeStyle = bgColor;
    context.stroke();
    context.restore();

    context.fillStyle = fontColor;
    context.textBaseline = 'middle';
    context.font = "120px 微軟雅黑";
    for (var i = 0; i < array.length; i++) {
        var text = array[i];
        length = context.measureText(text).width;
        context.fillText(text, (width - length) / 2, lineHeight * (i + 0.5));
    }
    billboard.s({
        'm.texture.image': canvas,
        'm.texture.offset': new mono.Vec2(0, 0.005),
        'm.texture.anisotropy': 8,
        'm.alignment': mono.BillboardAlignment.bottomCenter
    });

obj模型

圖片描述

這兩種屬於obj模型,是設計小姐姐作的,而後咱們經過make.Default.register函數定義模型,經過make.Default.load函數加載使用模型。

爲了使效果更逼真,咱們給模型作了環境貼圖。

object3d.setStyle('m.envmap.image', make.Default.getEnvMap('envmap5'));

圖片描述

動畫

單純的靜態圖看起來有些單調,因此咱們給連線加了動畫效果:找一張一半透明一半有顏色的圖片,做爲貼圖貼在連線上,利用動畫函數使貼圖不斷平移,就實現了下面的效果。
圖片描述

實體模型

最底層的模型採用了實體模型,真實感更強:
圖片描述

嵌套關係

上面也提到過,層與層、層內各個模塊中之間存在錯綜複雜的多層嵌套關係,爲了展示這種關係,那確定就要連線,話很少說,直接上圖。
圖片描述

線的類型有兩種,層與層之間的連線類型是link,每層模塊之間的連線類型是pathLink,建立pathLInk代碼以下:

createPathLink: function (data) {
    var box = main.sceneManager.getDataBox();
    var fromNode = main.sceneManager.getNodeByDataOrId(data.fromId);
    var toNode = main.sceneManager.getNodeByDataOrId(data.toId);
    var radius = data.path.radius || 3;
    var color = data.path.color || 'yellow';
    var endCap = data.path.endCap;
    var startCap = data.path.startCap;
    var linkType = data.routeType;
    var flow = data.path.flow || '';
    var workflowId = data.workflowId || ''; 
    if (fromNode && toNode) {
        var link = new mono.PathLink(fromNode, toNode, data.id);
        var plength = link.getPath().getLength();
        link.setRadius(radius);
        link.s({
            'm.type': 'phong',
            'm.color': color,
            'm.ambient': color
        });
        link.workflowId = workflowId;
        if (endCap) {
            var endCapSize = data.path.endCapSize || 10;
            var endCapR = data.path.endCapR || 2;
            link.setEndCap(endCap);
            link.setEndCapSize(endCapSize);
            link.setEndCapR(endCapR);
        }
        if (startCap) {
            var startCapSize = data.path.startCapSize || 10;
            var startCapR = data.path.startCapR || 2;
            link.setStartCap(startCap);
            link.setStartCapSize(startCapSize);
            link.setStartCapR(startCapR);
        }
        if (linkType) {
            link.setLinkType(linkType);
        }
        box.add(link);
    }
}

link類型連線與pathLink類型連線大致相同,之因此層與層之間選擇link類型,有兩個緣由:一是當鏡頭拉近時,link類型的連線粗細不會改變,二是便於控制拐點,就是下圖中的紅圈處。

圖片描述

link.setLinkType('control');//control屬性控制連線的拐點
link.setControls(controls);//controls爲數組

這樣就能夠呈現圖中的傘狀效果啦。

爲了增長點朦朧感以及讓傘狀效果更好,咱們特地添加了一點光環,有沒有感受金光從天而降呢?此時請想象本身45°角仰望天空,金光照在臉上。
圖片描述

流程動畫

基礎打好,下面就能夠加上動畫,執行流程了。先上圖:

圖片描述

點擊左邊的按鈕,出現圖中的白色小球,沿着連線運動,完整展示整個流程步驟。固然,鏡頭會隨着小球切換,這樣小球時刻在視線正中,媽媽不再用擔憂個人視線被擋住。

鏡頭切換的代碼也很簡單:

var pos = link.getPointAt(v);
workflowSphere.p(pos);
billboard.p(pos.clone().add(new mono.Vec3(0, 250, 0)));
var camera = main.sceneManager.network3d.getCamera();
camera.lookAt(pos);
camera.p(pos.clone().sub(this._cameraOffset));

數據

最後聊聊數據。爲了方(tou)便(lan),咱們將流程圖的全部數據都存放在後臺。在後端頁面,能夠設置流程圖的結構、邏輯、流程節點的樣式等。

圖片描述

利用Ajax獲取模型數據,而後三行代碼即可建造一個3D流程圖系統。

dataManager.addCategoryFromJson(loadData.categories);
dataManager.addDataTypeFromJson(loadData.datatypes);
dataManager.addDataFromJson(loadData.datas);

一樣,能夠在後端頁面設置連線的樣式、顏色、起點、終點等等,獲取到連線數據後,利用上文提到的方法即可繪製出所須要的連線。連動畫的起點、走向一樣能夠在後端頁面設置。

若是甲方爸爸以爲某個流程有問題,須要修改時,不要怕,默默打開後端頁面改幾個節點就行了。速度這麼快,快誇我快誇我。

總而言之,只須要經過數據配置便可生成不一樣的三維流程,知足客戶的各類需求。

對demo感興趣的同窗,能夠給我發郵件:tw-service@servasoft.com,甲方爸爸的數據不能給你,demo仍是能夠給大家看一眼的。

圖片描述

相關文章
相關標籤/搜索