1. 程式人生 > >基於 HTML5 Canvas 的病毒模擬視覺試驗檯

基於 HTML5 Canvas 的病毒模擬視覺試驗檯

前言

  2020 年 1 月 12 日,世界衛生組織以武漢病毒肺炎病例命名了一種病毒,2019新型冠狀病毒 ( 2019-nCoV ) 。隨著春運的到來,該病毒迅速的蔓延開來,大家都唯恐避之不及。病毒的爆發並不單單隻有中國這人口大國,縱觀整個地球,2020 年,還有很多國家也在“水深火熱”中努力進行著“自救”。美國,近幾個月來爆發了非常致命的流感--乙型流感病毒,據相關資料統計,到目前為止全美範圍已經有超 1300 萬人感染了該病毒, 12 萬人住院治療,死亡人數可能高達 6600 多人;波蘭,2019 年 12 月 31 日至 2020 年 1 月 4 日,該國盧布林省和大波蘭省發生 8 起 H5N8 亞型高致病性禽流感,此次疫情可能導致多達 4 萬隻禽類被宰殺,方圓3公里多達 35 萬隻家禽受到威脅;中國,農業農村新聞辦公室 2 月 1 日釋出,湖南省邵陽市雙清區發生一起家禽 H5N1 亞型高致病性禽流感疫情,養殖戶存欄肉雞 7850 只,發病死亡 4500 只,疫情發生後,當地按照有關預案和防治技術規範要求切實做好疫情處置工作,已撲殺家禽 17828 只,全部病死和撲殺家禽均已無害化處理......在病毒面前,人類真的很脆弱,此次新型冠狀病毒雖然致死率低,但傳染性極強,如果傳播過程中發生了可怕的變異,導致致死率提升,那麼造成的後果難以估量。如果大家早期能夠認識到病毒的危害,提高自我防範意識,那麼就能有效的控制疫情的蔓延。此次春節在家,發現大多數的長輩都對此次疫情不以為然,依舊到處串門喝茶聊天,進出人群密集的地方時,不戴口罩,多番勸阻無果,很是無奈,依舊有部分人不瞭解病毒的危害。此篇文章就以 HIV 病毒為例,採用 2/3D 結合的視覺化效果,直觀展示病毒的微觀世界。補充說明:人類免疫缺陷病毒 ( Human Immunodeficiency Virus;abbe:HIV ),即艾滋病 ( AIDS,獲得性免疫缺陷綜合徵) 病毒,屬逆轉錄病毒的一種。

demo: http://www.hightopo.com/demo/hiv-test-bed/

效果圖:

1.HIV 活性實驗臺

 

該模組主要模擬在不同環境不同試劑的情況下,病毒活性的變化。

功能點1:左側為實驗控制檯,可拖拽其值進度條來改變數值,通過一定的計算公式進而去動態修改 3D 場景中病毒的活性面板的相關顯示值。

功能實現:監聽 2D 圖紙的互動器,在圖元拖拽中進行去進行相關引數值的修改( addInteractorListener,簡寫為 mi ),接著通過模型中 Data 元素屬性變化監聽器( addDataPropertyChangeListener,簡寫為 md )去監聽每一次引數的變化,然後通過一定的計算公式去計算活性面板的最終顯示值,最後以資料驅動方式去修改活性面板的資料。

主要程式碼:

this.operator = { temperature: 60, humidity: 60, time: 25, sorbitol: 35, FBS: 50 }
// 溫度、溼度、時間、山梨醇、胎牛血清
this.g2d.dm().md(handleInterActivePanel, this);
function handleInterActivePanel(e) {
    // 溫度、溼度、時間、山梨醇、胎牛血清
    if (this.operator.hasOwnProperty(e.data.getTag()) && e.property === 'a:value') {
        this.operator[e.data.getTag()] = e.newValue;
        const operator = this.operator;
        let node = this.g3d.dm().getDataByTag('activePanel');
        let dataSource = node.a('dataSource');
        let calc = [
            {
                value: parseFloat((100
                    * (1 - operator.temperature / 100)
                    * (1 - operator.time / 60)
                    * (1 - operator.sorbitol / 100)
                    * (1 - operator.FBS / 100)
                    * (operator.humidity / 100)
                ).toFixed(2))
            },
            {
                value: parseFloat((90
                    * (1 - operator.temperature / 100)
                    * (1 - operator.time / 60)
                    * (1 - operator.sorbitol / 100)
                    * (1 - operator.FBS / 100)
                    * (operator.humidity / 100)
                ).toFixed(2))
            },
            {
                value: parseFloat((60
                    * (1 - operator.temperature / 100)
                    * (1 - operator.time / 60)
                    * (1 - operator.sorbitol / 100)
                    * (1 - operator.FBS / 100)
                    * (operator.humidity / 100)
                ).toFixed(2))
            },
            {
                value: parseFloat((10
                    * (operator.temperature / 100)
                    * (operator.time / 60)
                    * (operator.sorbitol / 100)
                    * (operator.FBS / 100)
                    * (1 - operator.humidity / 100) + 0.01
                ).toFixed(2))
            },
        ]
        dataSource = dataSource.map((i, index) => {
            return {
                rising: i.value > calc[index].value,
                value: calc[index].value,

            }
        })
        node.a('dataSource', []);
        node.a('dataSource', dataSource);
    }
}

 

功能點2:放大鏡檢視。

功能實現:根據放大鏡左側倍數控制器的值去動態設定放大鏡中圖元的縮放值。

主要程式碼:

// 獲取病毒圖元
this._virusNode = virus2D.dm().getDataByTag('virusNode');
// 對圖元進行縮放
function setScale(value) {
    this._virusNode.setScale(value, value);
}
this.g2d.dm().mp(function (e) {
    if (e.property === "a:virusScale") {
        if (this.virus2D) {
            setScale(e.newValue);
       this._virusNode.setScale(value, value);
} } }, this);

功能點3:病毒成分剖面示意圖及其 RNA 鏈。 2D 及 3D 的效果展示,使微觀病毒更加具象化,幫助人們更加清晰的認識病毒。

功能點4: 3D 場景中病毒的呼吸效果。

功能實現:使用 HT 的動畫功能,不斷的去設定病毒圖元自身的縮放值。

主要程式碼:

let params = {
    duration: 10000, // 動畫週期毫秒數,預設採用`ht.Default.animDuration`
    easing: (t) => { return t }, // 動畫緩動函式,預設採用`ht.Default.animEasing`
    action: (v, t) => {
        this.virus.forEach((i, index) => {
            let count = 0;
            if (i.a('count')) {
                count = i.a('count');
            } else {
                count = 0;
            }
            count += 0.5;
            let scale = this.virusScales[index] +
                0.1 *
                Math.cos(
                    (((count % 36) * Math.PI) / 180) * 10 +
                    ((360 / this.virus.length) * index * Math.PI) /
                    180
                );
            i.eachChild(data => {
                data.setScale3d(scale, scale, scale);
            });
            i.a('count', count)
        })
    },
    finishFunc: () => {
        if (this._continuous) {
            this.breating();
        }
    }, // 動畫結束後呼叫的函式。
}
this.anim = ht.Default.startAnim(params);

 

2.免疫系統侵入演示

 

動畫步驟描述:

① 病毒侵入,免疫啟用
開始:場景中只有三個白細胞(兩個小的白細胞離大號的較遠);
過程:病毒漸顯(粉色顆粒,上面無附著抗體標記);
結束:場景中只存在三個白細胞和病毒
② 白細胞釋放趨化因子和增值化學物質
開始:場景中有三個白細胞和六個病毒;
過程:趨化因子從大號白細胞內部釋放出來,漸顯,而後另外兩個白細胞向大號靠近到一定距離,然後趨化因子漸隱消失
結束:場景中存在三個白細胞(兩個小的白細胞靠近大號的)、六個病毒
③ 白細胞產生抗體標記靶向細菌/病毒
開始:場景中有三個白細胞(兩個小的白細胞靠近大號的)和六個病毒;
過程:抗體標記從大號白細胞裡漸顯飛出,最後附著在病毒上,此時出現提示面板(內容:病毒/細菌被白細胞標記抗體),最後面板漸隱
結束:場景中存在三個白細胞(兩個小的白細胞靠近大號的)、六個病毒和抗體標記(附著在病毒上)
④ 白細胞吞噬靶向細胞/病毒
開始:場景中存在三個白細胞(兩個小的白細胞靠近大號的)、六個病毒和抗體標記(附著在病毒上)
過程:大號白細胞出現提示面板(內容:白細胞被吸引到標記抗體處,面板漸顯漸隱後,大號白細胞移動至四個病毒區域,二號白細胞移動至兩個病毒區域,三號朝病毒區域中心移動輕微移動一小段,稍微停頓後,白細胞恢復初始位置,病毒、抗體標記消失
結束:場景中只存在三個白細胞
⑤ HIV 病毒侵入進入白細胞
開始:場景中存在三個白細胞
過程:出現幾個病毒,然後HIV病毒漸顯,再然後進入到一號白細胞內部
結束:場景中存在三個白細胞,一個 HIV 病毒,兩三個粉色病毒
⑥ HIV 病毒在白細胞內複製,白細胞死亡
開始:場景中存在三個白細胞,一個 HIV 病毒(在一號白細胞內部),兩三個粉色病毒
過程:HIV 病毒開始複製(體現在數量增多),然後三個白細胞同時縮小到原來的一半
結束:場景中存在三個白細胞(體積縮小),三個 HIV 病毒
⑦ HIV 病毒跑出,細菌增生免疫系統破壞成功
開始:場景中存在三個白細胞(體積縮小),三個 HIV 病毒
過程:HIV病毒跑出一號白細胞,同時白細胞漸隱直至消失,而後粉色病毒增多
結束:場景中只存在三個 HIV 病毒,多個粉色病毒

動畫實現:ht.Default.startAnim 的動畫函式,示例程式碼如下:

ht.Default.startAnim({
    frames: 12, // 動畫幀數
    interval: 10, // 動畫幀間隔毫秒數
    easing: function(t){ return t * t; }, // 動畫緩動函式,預設採用`ht.Default.animEasing`
    finishFunc: function(){ console.log('Done!') }, // 動畫結束後呼叫的函式。
    action: function(v, t){ // action函式必須提供,實現動畫過程中的屬性變化。
   ...
    }
});

除了以上動畫外,該模組還新增了兩個控制項:控制動畫播放速度(修改動畫的 duration 引數值)及 3D 場景的視角(修改 eye)。

實現程式碼:

function getPositionByZoom(arr, zoom) {
    return [arr[0] * zoom, arr[1] * zoom, arr[2] * zoom];
}
this.g2d.dm().mp(function (e) {
    if (e.property === 'a:stepIndex') {
        // 做演示動畫
        this.stepIndex = e.newValue;
        this['anim' + (e.newValue + 1)]();
    } else if (e.property === 'a:screenZoom') {
        let value = e.newValue;
        if (this._eye) {
            let newEye = getPositionByZoom(this._eye, value);
            this.g3d.setEye(newEye);
        }
    } else if (e.property === 'a:playSpeed') {
        this.speed = 1 / e.newValue;
    }
})

 

3.藥物抑制原理演示

  該模組主要演示生物酶抑制劑和化學消毒/去汙藥劑對病毒活性的影響。通過改變試劑的用量來模擬計算出病毒的活性率、複製速度、感染性、突變機率。

  動畫演示中涉及的 3D 圖元的位移方法。通過繪製一條管道軌跡線來實現。

// 偏移動畫
let g3d = this.g3d;
let params = {
    frames: 100, // 動畫幀數
    interval: 30, // 動畫幀間隔毫秒數
    easing: (t) => { return t }, // 動畫緩動函式,預設採用`ht.Default.animEasing`
    action: (v, t) => {
        let pipe;
        this.moveNodes.forEach((i, index) => {
            if (index < 2) {
                pipe = this.pipe1;
            } else {
                pipe = this.pipe2;
            }
            let length = g3d.getLineLength(pipe),
                offset = g3d.getLineOffset(
                    pipe,
                    length * t
                ),
                point = offset.point,
                px = point.x,
                py = point.y,
                pz = point.z,
                tangent = offset.tangent,
                tx = tangent.x,
                ty = tangent.y,
                tz = tangent.z;
            i.p3(px, py, pz);
            i.lookAt([px + tx, py + ty, pz + tz], 'right');
            i.a('angle', t * Math.PI * 120);
        })
    },
    finishFunc: () => {
        if (this._continuous) {
            this.move();
        }
    }, // 動畫結束後呼叫的函式。
}
this.anim = ht.Default.startAnim(params);

 

  現在新型冠狀病毒愈演愈烈,感染的人越來越多,但是很多人尤其是中老年人還沒有意識到嚴重性,依然堅持過完年要走親訪友的觀念,這走走那串串。為了避免感染新型冠狀病毒,如何勸說家人不走親訪友呢?今天就來跟大家分享下。

1.告訴家人目前新型冠狀病毒疫情的最新情況,告訴他們每天有多少病例增加,讓他們意識到疫情的傳播速度很快,很容易被感染的,如果出去走親訪友,被傳染的概率會增加。

2.單純的數字可能他們還不以為然,認為全國十幾億人口,自己“中獎機率”很低,沒啥概念,這時候我們可以給他們看看更為直觀的疫情地圖。( http://www.hightopo.com/demo/coronavirus/ )這裡面有每天最新的視覺化資料,幫助大家更為直觀瞭解當前疫情蔓延的分佈趨勢。

3.新聞報道!一般中老年人更相信電視上的新聞,讓他們瞭解病毒的嚴重性,從而打消出門走親訪友的念頭。

4.藥店的相關預防藥物及醫用口罩等已經賣空了,讓他們知道周圍的人都已經在進行自身防護了,建立家人自身防範的意識,從而自覺放棄走親訪友。

5.告知各地封村封路的訊息,讓他們知道疫情的嚴重性。

6.給他們看些硬核標語。

  • 口罩還是呼吸機,您老看著二選一;
  • 發燒不說的人,都是潛伏在人民群眾中的階級敵人;
  • 老實在家防感染,丈人來了也得攆;
  • 今年過年不串門,來串門的是敵人,敵人來了不開門;
  • 串門就是互相殘殺,聚會就是自尋短見;
  • 現在請吃飯的都是鴻門宴
  • ......

  這個春節,一場突如其來的疫情防控阻擊戰,在中華大地驟然打響,這是一場沒有硝煙的戰爭,無論是醫護人員,還是基礎工作者,他們在疫情爆發的那一刻,就拿起了“武器”奔赴“戰場一線”。病毒並不會因為他們是醫護人員而“網開一面”,歲月靜好,是因為有人在為我們負重前行,感謝那些在疫情中為我們奔赴前行的人,在疫情面前,我們沒有一個人能置身事外。“宅”在家,這是對自己負責,對他人負責,更是對社會、對國家最大的支援。中華兒女從不畏懼任何困難,不會退縮,我們堅信這場戰爭我們肯定能贏,也必須要