數(shù)字孿生下的孿生風機,前端技術介紹

風機.png

上一篇文章我們介紹了數(shù)字孿生巴粪,和該技術下孿生風機的諸多優(yōu)點通今。本篇文章向大家介紹下孿生風機用了哪些前端技術?前端效果是如何實現(xiàn)的肛根?

一辫塌、Canvas

簡介

在web中,實現(xiàn)2D基本圖形及動畫效果派哲,首先會想到使用canvas臼氨。例如上圖,實現(xiàn)一個可以實時顯示風向角變化的效果圖芭届。canvas非常靈活储矩,能夠很好地融合JavaScript代碼并在瀏覽器內(nèi)繪制華麗的圖形感耙,擁有多種繪制路徑、形狀持隧、字符以及添加圖像等方法即硼。
面對各種復雜的圖形及效果,我們可以采用canvas框架屡拨,例如Konva只酥,它可以輕松的實現(xiàn)桌面應用和移動應用中的圖形交互交互效果,可以高效的實現(xiàn)動畫呀狼,變換裂允, 節(jié)點嵌套, 局部操作哥艇,濾鏡绝编,緩存,事件等功能貌踏,不僅僅適用于桌面與移動開發(fā)十饥, 還有更為廣泛的應用。

實現(xiàn)

在實現(xiàn)動畫實時變化效果時哩俭,如果每次風向發(fā)生改變绷跑,都需要重繪圖形,效果顯示難免有些單調(diào)凡资。重新繪圖的變化過程稱為突變動畫砸捏。

反面教材-突變動畫

我們需要的是平滑的過渡效果,例如隙赁,風向角在上一時刻是36.89度垦藏,下一時刻是76.84度。動畫效果由36.89度漸變到76.84度的平滑效果伞访。
平滑動畫

為避免突變動畫的情況掂骏,我們需要在componentWillUpdate中監(jiān)聽角度參數(shù)rotation的變化,當有新的角度參數(shù)傳入的時候厚掷,需要重新繪制圖形并將新的參數(shù)傳入弟灼。
代碼如下:

componentWillUpdate(nextProps) {
    if (nextProps.rotation !== this.props.rotation) {
      this.layer.destroy()
      this.tween.destroy()
      this.drawWind(nextProps)
    }
  }
//旋轉(zhuǎn)部分初始角度賦值為當前rotation。
 let lineGroup = new Konva.Group({
      x:radius,
      y:radius,
      rotation: this.props.rotation,//未變化時采用this.props值冒黑。動畫處用nextProps
    })

//動畫部分旋轉(zhuǎn)角度賦值為新的rotation田绑。
    this.tween = new Konva.Tween({
      node: lineGroup,
      easing: Konva.Easings.Linear,
      duration: 0.5,
      rotation: nextProps.rotation ? nextProps.rotation : nextProps.rotation === 0 ? 0 : this.props.rotation,
      onFinish: () => {
        this.tween.destroy()
      }
    });

二、Three.js

簡介

Three.js是基于原生WebGL封裝運行的三維引擎抡爹,在所有WebGL引擎中掩驱,Three.js是國內(nèi)文檔資料最多、使用最廣泛的三維引擎;Three.js是純渲染引擎欧穴,而且代碼易讀民逼,適合作為學習WebGL、3D圖形涮帘、3D數(shù)學應用的平臺拼苍,也可以做中小型的重表現(xiàn)的Web項目。


風機

實現(xiàn)

風機模型加載完畢后调缨,當鼠標移動到風機各個零部件時映屋,所選部件增加線框以表示為選中狀態(tài)。如果在此之前有選中其它部件同蜻,需移除其它部件的選中狀態(tài)。當鼠標移出該部件的時候早处,將其線框移除湾蔓。


選中狀態(tài)

代碼如下:監(jiān)聽鼠標事件的onMouseMove。

  // 鼠標移入事件
    this.mouseMove = (event) => {
      //點擊射線
      let raycaster = new THREE.Raycaster();
      // ?????? 注意此處的mouse必須設置砌梆,這樣下面才能判斷當前選中模型Group的單個組員
      let mouse = new THREE.Vector2();
      //將鼠標點擊位置的屏幕坐標轉(zhuǎn)成threejs中的標準坐標,具體解釋見代碼釋義
      mouse.x = (event.offsetX / width) * 2 - 1;
      mouse.y = -(event.offsetY / height) * 2 + 1;
      //新建一個三維單位向量 假設z方向就是1 
      //根據(jù)照相機默责,把這個向量轉(zhuǎn)換到視點坐標系
      let vector = new THREE.Vector3(mouse.x, mouse.y, 1).unproject(camera)
      //通過鼠標點擊的位置(二維坐標)和當前相機的矩陣計算出射線位置
      raycaster.setFromCamera(mouse, camera);
      //在視點坐標系中形成射線,射線的起點向量是照相機, 射線的方向向量是照相機到點擊的點咸包,這個向量應該歸一標準化桃序。
      raycaster.set(camera.position, vector.sub(camera.position).normalize())
      //射線和模型求交,選中一系列直線
      // 存放旋轉(zhuǎn)部分點擊
      let intersectsFlabellum = raycaster.intersectObjects(flabellum.children, true)
      // 存放旋轉(zhuǎn)部分之外的點擊
      let intersectsObject = raycaster.intersectObjects(this.object.children, true)
      if (intersectsFlabellum.length && !intersectsObject.length) {
        if (intersectsFlabellum[0].object.name === '扇葉' && intersectsFlabellum.length < 3) {
          if (this.state.mouseOver !== '扇葉') {
            this.setState({ mouseOver: '扇葉' })
            this.scene.remove(hubLineGroup)
          }
        } else if (intersectsFlabellum[0].object.name === '輪轂') {
          if (this.state.mouseOver !== '輪轂') {
            this.setState({ mouseOver: '輪轂' })
            this.scene.add(hubLineGroup)
          }
        } else {
          this.scene.remove(hubLineGroup)
          if (!this.state.mouseSelect) {
            this.setState({ mouseOver: '', control: true })
          } else {
            this.setState({ mouseOver: '' })
          }
        }
      } else {
        this.scene.remove(hubLineGroup)
      }
      
       if (intersectsObject.length) {
        this.scene.remove(pitchGroup)
        this.scene.remove(hubLineGroup)
        if (intersectsObject[0].object.name === '主軸') {
          if (this.state.mouseOver !== '主軸') {
            this.setState({ mouseOver: '主軸' })
            this.scene.add(mainAxleGroup)
            this.scene.remove(gearGroup)
            this.scene.remove(powerGroup)
          }
        } else if (intersectsObject[0].object.name === '齒輪結構') {
          if (this.state.mouseOver !== '齒輪結構') {
            this.setState({ mouseOver: '齒輪結構' })
            this.scene.add(gearGroup)
            this.scene.remove(mainAxleGroup)
            this.scene.remove(powerGroup)
          }
        } else if (intersectsObject[0].object.name === '發(fā)電機箱') {
          if (this.state.mouseOver !== '發(fā)電機箱') {
            this.setState({ mouseOver: '發(fā)電機箱' })
            this.scene.add(powerGroup)
            this.scene.remove(mainAxleGroup)
            this.scene.remove(gearGroup)
          }
        } else {
          if (!this.state.mouseSelect) {
            this.setState({ mouseOver: '', control: true })
          } else {
            this.setState({ mouseOver: '' })
          }
          this.scene.remove(mainAxleGroup)
          this.scene.remove(gearGroup)
          this.scene.remove(powerGroup)
        }
      } else {
        this.scene.remove(mainAxleGroup)
        this.scene.remove(gearGroup)
        this.scene.remove(powerGroup)
      }
      
            if (!intersectsObject.length && !intersectsFlabellum.length) {
        if (!this.state.mouseSelect) {
          this.setState({ mouseOver: '', control: true })
        } else {
          this.setState({ mouseOver: '' })
        }
      }
    }

鼠標點擊查看詳細信息烂瘫,鼠標按下的時候媒熊,對此時正處于選中狀態(tài)的部件進行動畫處理。對于信息量較少的部件坟比,需要給一個小彈窗來顯示信息即可芦鳍。


點擊彈窗

代碼如下:監(jiān)聽鼠標事件onClick。

 // 點擊事件  
    this.clickEvent = (event) => {
      // 點擊扇葉停止動畫葛账。點擊扇葉并且下一次不點擊扇葉開始動畫柠衅。
      if (this.state.isClickLeaf) {
        this.setState({ isClickLeaf: false })
        this.animate()
      }
      if (this.state.mouseOver) {
        if (this.state.mouseOver === '扇葉') {
          cancelAnimationFrame(this.animateId)
          $('.popup').css({
            left: event.offsetX,
            top: event.offsetY - $('.popup').height(),
          })
        } else if (this.state.mouseOver === '輪轂') {
          $('.popup').css({
            left: event.offsetX,
            top: event.offsetY - $('.popup').height(),
          })
        } else if (this.state.mouseOver === '主軸') {
          $('.popup').css({
            left: event.offsetX,
            top: event.offsetY - $('.popup').height(),
          })
        } else if (this.state.mouseOver === '齒輪結構') {
          this.setState({ mouseSelect: '齒輪結構', control: true })
        } else if (this.state.mouseOver === '發(fā)電機箱') {
          this.setState({ mouseSelect: '發(fā)電機', control: true })
        } else if (this.state.mouseOver === '偏航系統(tǒng)') {
          this.setState({ mouseSelect: '偏航系統(tǒng)', control: true })
        }
      } else {
        if (this.state.mouseSelect !== '齒輪結構' && this.state.mouseSelect !== '偏航系統(tǒng)' && this.state.mouseSelect !== '發(fā)電機') {
          this.setState({ mouseSelect: '', control: true })
        }
      }
    }

當所選部件信息量較大時,如下顯示籍琳。


復雜點擊

結束語

web頁面因Canvas和Three.js在2D和3D方面的支持變得豐富多彩菲宴,妙趣橫生。生動豐富的數(shù)據(jù)展示趋急,方便了我們對風機的數(shù)據(jù)的實時監(jiān)測喝峦。
至此,本文和本系列文章已經(jīng)告一段落了宣谈,希望可以幫助讀者更加了解我們的孿生風機愈犹。有任何問題,歡迎聯(lián)系我們!關注一下漩怎,下次找我不迷路勋颖!如果覺得文章有可取之處,還請多多點贊勋锤!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饭玲,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子叁执,更是在濱河造成了極大的恐慌茄厘,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谈宛,死亡現(xiàn)場離奇詭異次哈,居然都是意外死亡,警方通過查閱死者的電腦和手機吆录,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進店門窑滞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人恢筝,你說我怎么就攤上這事哀卫。” “怎么了撬槽?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵此改,是天一觀的道長。 經(jīng)常有香客問我侄柔,道長共啃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任暂题,我火速辦了婚禮勋磕,結果婚禮上,老公的妹妹穿的比我還像新娘敢靡。我一直安慰自己挂滓,他們只是感情好,可當我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布啸胧。 她就那樣靜靜地躺著赶站,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纺念。 梳的紋絲不亂的頭發(fā)上贝椿,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天,我揣著相機與錄音陷谱,去河邊找鬼烙博。 笑死瑟蜈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的渣窜。 我是一名探鬼主播铺根,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼乔宿!你這毒婦竟也來了位迂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤详瑞,失蹤者是張志新(化名)和其女友劉穎掂林,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坝橡,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡泻帮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了计寇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刑顺。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖饲常,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情狼讨,我是刑警寧澤贝淤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站政供,受9級特大地震影響播聪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜布隔,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一离陶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧衅檀,春花似錦招刨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至杉适,卻和暖如春谎倔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背猿推。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工片习, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓藕咏,卻偏偏與公主長得像状知,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子侈离,可洞房花燭夜當晚...
    茶點故事閱讀 43,514評論 2 348

推薦閱讀更多精彩內(nèi)容