1. ホーム
  2. Web制作
  3. html5

HTML5 WebGLを用いた医療用物流システム

2022-01-28 17:02:45

前置き

IoT(Internet of Things)とは、簡単に言うと、インターネットを介してモノとモノがつながることです。世の中のあらゆるものが、データの変化によってインテリジェントに管理できるようになります。IoTの台頭は、医療業界において命を救う可能性を持っています。
IoTは、ユーザーの情報を収集し、リアルタイムで診断していくため、間違いなく医療に包括的な未来をもたらすでしょう。ここでは、私が最近構築した医療用物流システムを見てみましょう。

htのオフィシャルサイトにリンクします。 http://www.hightopo.com/cn-index.html

デモへのリンクです。 https://www.hightopo.com/demo/pivas/

実装プロセス

光源の追加

 実は元のシーンは全体的にとても暗いので、ライティング効果で全体を照らし、現実のシーンに近づける必要がありました。

 比較して見ましょう。

光のいくつかの属性。

typeは光の種類を表します

colorは光の色を表します。

intensityは光の強さ(1が最大)

range は範囲を表します。

addLight() {
        const skyBox = this.dm.getDataByTag('skyBox')

        // Limit the view to the sky ball
        this.gv.setSkyBox(skyBox)
        const light = new ht.Light()
        const lightSource = this.dm.getDataByTag('sunlight').p3()

        const config = {
            'light.type': 'point',
            'light.color': 'white',
            'light.intensity': 0.3,
            'light.range': 10000
        }

        light.s(config)
        light.p3(lightSource)this.dm.add(light)
 }

モノを見る

 左下にある小さなウィンドウをご覧ください。実はこれは左下に配置された別の3Dシーンで、どちらもdeserializeを使っています。

 flyToメソッドは、メディカルボックスの移動のための位置決めに使用されるため、ここで使用されています。

var renderCanvas = function (medical, duration) {
    ht.Default.startAnim({
       duration,
       easing(v, t) {
         return t
       },
       action(v, t) {
         outScreenG3d.flyTo(medical, { direction: [-5, 3, 5], distance: 300 })
       }
    })
 }

カプセル化されたアニメーション

これだけ多くのアニメーションを実装しようと思うと、まず思いつくのは、物体を次々と動かす処理です。医療キットが歩くときの動き、エレベーターが持ち上がるときの動き、コンベヤーが医療キットを運ぶときの動きをカプセル化することができるのです。

図のように医療キットは常に動いているので、歩行アニメーションを定義し、医療キットが歩行するたびに、その移動距離、移動方向、アニメーションの構成をパラメータとして渡します。

ここで指定するパラメータ

1. ノード(対応する要素)

2.fn(アニメーション実行後のコールバックを行う関数)。

3.コンフィグ(アニメーションの設定)

4.coord(方向軸)

// Walk animation
walkAnim(node, fn, config, coord) {
  const { duration, space } = config
  const positionArray = node.p3()
  let isShadow = false
   let ShadowNode = null
    // If the moving element is an icu cart or supply cart, get its shadow to follow the element
   if (node.getTag() === 'supply' || node.getTag() === 'icuCar') {
     isShadow = true
     ShadowNode = this.dm.getDataByTag(`${node.getTag()}Shadow`)
   }

   ht.Default.startAnim({
     duration,
     easing: function (t) {
        return t
      },
      action(v, t) {
        if (coordinate === 'x') {
            node.p3(positionArray[0] + t * space, positionArray[1], positionArray[2])
            isShadow && ShadowNode.p3(positionArray[0] + t * space, positionArray[1], positionArray[2])
        } else if (coord === 'y') {
            node.p3(positionArray[0], positionArray[1] + t * space, positionArray[2])
            isShadow && ShadowNode.p3(positionArray[0], positionArray[1] + t * space, positionArray[2])
         } else {
           node.p3(positionArray[0], positionArray[1], positionArray[2] + t * space)
           isShadow && ShadowNode.p3(positionArray[0], positionArray[1], positionArray[2] + t * space)
         }
      },
      finishFunc() {
         typeof fn === 'function' && fn(node)
      }
   })
}

オブジェクト間エフェクト

エレベーターの昇降は様々なものに影響を与えます。例えば、周波数テーブルの移動はコンベアと医療箱を一緒に運んでしまいます。ここでは、sethost adsorption法(吸着:ノードがホストを指定し、ホストがノードに影響を与える変更を行う)を使用しています。

これが非常に適切なシナリオはたくさんあります。エレベーターに医療キットと周波数表を載せて上下させる必要があるのですが、キットをコンベヤーに乗せるとキットは動かなければならず、本当にコンベヤーがキットを動かしているように感じられるのです。

ここで説明するパラメータは

1. ノード(操作するエレベータ要素)

2. medicalKit(医療キット)

3. fn(アニメーション実行後にコールバックを行う関数)。

4.status(エレベーターが上下している状態)

5.コンフィグ(アニメーション設定)

// Elevator lift animation
    elevatorAnim(node, medicalKit, fn, status, config) {
        const self = this
        // Get the index of the elevator so that the corresponding frequency table moves with it
        const elevatorIndex = node.getTag().replace(/[^0-9]/ig, '') - 0
        // Get the index of the medical kit to control the distance of the elevator lift
        const medicalKitIndex = medicalKit.getTag().replace(/[^0-9]/ig, '') - 0
        const positionArray = node.p3()
        const station = self.dm.getDataByTag(`station${elevatorIndex}`)
        //Absorb hosts
        station.setHost(node)
        medicalKit.setHost(node)
        // Set the elevator state
        if (elevatorIndex === 3) self.elevatorRunning = true
        // the lifting distance is down when the status is 0 the distance to the lowest part is fixed so you only need to control the rising distance
        const medicalKitLevel = self.returnMedicalKitLevel(medicalKitIndex)
        // Properties of the elevator
        // the position of the lowest point Lowest
        // If there is a track, go to the position of the track, otherwise follow the number of levels orbitalP
        // position of the first floor distance
        let space
        const addSpace = medicalKitIndex === 7 ? 100 : 0
        if (status == 1) {
            space = config.orbitalP ? config.orbitalP : config.distance + addSpace + (400 * medicalKitLevel)
        } else {
            space = config.Lowest
        }
        // The medical kit does not do anything when it is down
        if (status === 0) {
            medicalKit.setHost()
        }
        return ht.Default.startAnim({
            duration: config.orbitalP ? 2000 : (medicalKitLevel === 0 && elevatorIndex == 3 ? 700 : 2500 + (medicalKitLevel * 1000)),
            action(v, t) {
                node.p3(
                    positionArray[0],
                    positionArray[1] + ((space - positionArray[1]) * t),
                    positionArray[2]
                )
            },
            finishFunc() {
                station.setHost()
                typeof fn === 'function' && fn(node)
            }
        })
    }

アニメーションの方法

 アニメーション中に処理する必要がある問題のひとつに、エレベーターアニメーションの待機があります。メディカル・ボックスは、アニメーション中にエレベーターが上昇しているかどうかを判断する必要があり、もし地上に出ていない場合は待機させる必要があります。

 私の考えでは、医療用ボックスがエレベーターから少し離れたところで、エレベーターが上昇状態かどうかを判断し、上昇状態であれば、アニメーションの一時停止メソッドを呼び出す必要があります。

 elevatorRunning が false の場合は、エレベーターが動いていないことを意味し、そうでない場合は動いていることを意味します。

 エレベーターのアニメーションが始まるとこの変数をtrueに、終わるとfalseに設定し、状態を監視できるようにします。

 ht.Default.startAnim メソッドは、アニメーションの状態をポーリングし、アクションを起こすために action メソッドを使用するインスタンスを返します。

 elevatorRunning が true の場合、 anim.pause() を使って現在のアニメーションを一時停止します。

 elevatorRunning が false の場合、 anim.resume() で現在のアニメーションを再開します。

const anim = ht.Default.startAnim({
  duration,
  action(v, t) {
    node.p3(
       positionArray[0],
       positionArray[1],
       positionArray[2] - (tpMax - positionArray[2]) * t
     );
     if (index > 1 && self.elevatorRunning === true) {
         if (node.p3()[2] <= stopMax) {
           anim.pause();
           const t = setInterval(() => {
             if (self.elevatorRunning === false) {
                anim.resume();
                clearInterval(t);
               }
           }, 100);
       }
    }
   },
   finishFunc() {
     typeof fn === "function" && fn();
   }
});

イベントリスニング(Publish、Subscribe)

 なぜなら、現在の何らかのアニメーションの終了をリッスンし、カメラシフトを実行する必要があるからです。

 このように、1つ目の3Dシーンのキューテキストアニメーションの終了をリッスンして、2つ目の3Dシーンの表示を実行する必要があるのです。この2つは別のシーンなので、コールバックではリスニングできないので、ここではイベントバスのeventBusを使用しています。

 ここでは、eventBusの使い方を説明します。第1引数にリッスンする登録関数名、第2引数にコールバック関数を指定します。

// eventbus Listening for events
eventbus.on('animation1', _ => {
  const medical = dm.getDataByTag('medicalKit1')
  renderView(medical, dm, gv)
})

ここでは、eventBusの発火を利用しています。最初のパラメータはトリガーする関数名、2番目はその関数に発火させるパラメータを表します。

// Trigger the event
eventbus.emit("animation1", null); 

概要

 このデモをやってみて、HT for Webを使いこなせるようになっただけでなく、Internet of Thingsについても理解が深まりました。

 自分の技術によって、人々の暮らしに役立つもの、より良いものを作ることができる時代に、フロントエンドに携わる者として、とても誇らしい気持ちになりました。

 私のデモを見て、インスピレーションを得るとともに、不可能を可能にし、社会に貢献できることを信じてほしいです。