Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

Prefacio

La energía eólica es un tipo de energía limpia en desarrollo, es inagotable e inagotable. Por supuesto, al construir un parque eólico, primero se deben considerar las condiciones meteorológicas y sociales naturales. En los últimos años, la energía eólica marina y terrestre de China se ha desarrollado rápidamente. El agua de mar y la tierra proporcionan una buena garantía geológica para nuestra generación de energía eólica. Son estos sitios los que proporcionan energía inagotable para nuestra energía eólica. Ahora estamos trabajando duro para explorar estas áreas.

En el artículo que compartí hoy, utilicé  un sistema de visualización creado por  el producto  HT para Web  de Hightopo , que realizó el flujo general del parque eólico y permitió que todos vieran un sistema completo de vista previa de energía eólica.

Proceso rudo

A continuación se muestra el diagrama de flujo de todo el proyecto. Podemos ingresar a la página de distribución del sitio y a la página de control centralizado desde la página de inicio.

La página de distribución del sitio también incluye dos escenas 3D diferentes, a saber, el aeropuerto de energía eólica terrestre y el aeropuerto de energía eólica marina. Al hacer clic en los dos campos de viento en 3D, eventualmente ingresará a la escena de la turbina de viento en 3D.

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Análisis de implementación:

Página de inicio:

1. Efecto de mapa mundial

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

Dirección de vista previa de la operación dinámica: https://www.hightopo.com/demos/index.html

2. Efecto mapa de China

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

3. Efecto de mapa de la ciudad

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Página del centro de control centralizado (sin efecto de animación):

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Página de distribución de campo (sin efecto de animación):

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Aeropuerto Landwind:

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Aeropuerto de Haifeng:

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Código

Podemos ver que la tierra en la página de inicio tiene tres estados en perspectiva, mapa del mundo, mapa de China y mapa de la ciudad. Haga clic en cada cámara de estado irá a la posición correspondiente. Antes de eso, debemos guardar el centro  y el  ojo correspondientes de antemano  .

Será mejor que creemos un nuevo   archivo data.js , dedicado a proporcionar datos.

El pseudocódigo relevante es el siguiente:

// 记录位置
var cameraLocations = {
    earth: {
        eye: [-73, 448, 2225],
        center: [0, 0, 0]
    },

    china: {
        eye: [-91, 476, 916],
        center: [0, 0, 0]
    },

    tsankiang: {
        eye: [35, 241, 593],
        center: [0, 0, 0]
    }
};

Bueno, con los datos. Deberíamos escuchar los eventos a continuación. Podemos hacer clic en el botón o hacer clic en el área resaltada (solo se puede hacer clic en el mapa del mundo) para ingresar a la perspectiva del mapa de China.

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Primero podemos obtener estos dos nodos y luego realizar el mismo procesamiento en sus eventos de clic. Sin embargo, creo que este enfoque se puede optimizar y reemplazar con una nueva forma de pensar.

Primero podemos filtrar los eventos. Creamos dos arreglos. Uno contiene los  eventos ejecutables como  click y onEnter , y el otro contiene todos los nodos que pueden disparar el evento. Esto puede ayudarnos a mantener, pero también a aclarar la estructura.

En la siguiente figura, podemos ver que si el nodo actual no tiene permiso de evento o el evento actual en sí mismo no tiene permiso, se filtrará. Si todo se puede devolver correctamente, ejecute el evento correspondiente.

Frontera tecnológica: parque eólico 3D basado en HTML5 WebGL

 

Siempre que el nodo que estamos ejecutando actualmente cumpla con los requisitos, pasaremos el evento (evento en ejecución actualmente) y la etiqueta (etiqueta de nodo) a la función de ejecución nodeEvent para su ejecución. De esta manera, no se desperdiciarán recursos para hacer frente a eventos o nodos no válidos.

¡Veamos cómo  lo maneja nodeEvent  a continuación!

El pseudocódigo relevante es el siguiente:

/**
 * 气泡事件
 * @param { string } event 当前事件
 * @param { string } propertyName 当前节点标签
 */
bubblesEvent(event, propertyName) {
    var dm = this.dm
    var account = dm.getDataByTag('account')
    var currentNode = dm.getDataByTag(propertyName)
    var self = this

    var clickData = function() {
        // 执行清除动作
        self.clearAction()
    }

    var onEnter = function() {
       // do something
    }

    var onLeave = function() {
    // do something
    }

    var allEvent = { clickData, onEnter, onLeave }

    allEvent[event] && allEvent[event]()
}

Como puede ver, podemos usar la  concatenación de cadenas propertyName (etiqueta de nodo)  para formar un nombre de método. Por ejemplo, la etiqueta de nodo que se obtiene actualmente es  bubbles, después de  este [`$ {ownName} Event`] , se  obtiene  el método este ['bubblesEvent']  . Por supuesto, este método está definido de antemano.

En el método de nodo específico, creamos la función de evento correspondiente. Según el evento  pasado  para determinar si existe un método correspondiente. Ejecute si hay alguno; de lo contrario, devuelva  falso  . Las ventajas de esto son: desacoplamiento, estructura simple y posicionamiento rápido de problemas.

Sin embargo, si lo pensamos detenidamente, cuando hacemos clic en el mapa del mundo y el mapa de China, ¡las funciones son similares! ¡Si podemos fusionarlos, será mucho más conveniente! ! Modifiquemos el código.

El pseudocódigo relevante es el siguiente:

/**
  * 执行节点事件
  */
function nodeEvent(event, propertyName) {
    // 过滤是否有可以合并的事件
    var filterEvents = function(propertyName) {
        var isCombine = false
     var self = this
        if (['earth', 'china'].includes(propertyName)) {
            self.changeCameraLocaltions(event, propertyName)
            isCombine = true
        }

        return !isCombine
    }
   var eventFun = this[`${propertyName}Event`]
   // 执行对应的节点事件
   filterEvents(propertyName) &&
   eventFun &&
   eventFun(event, propertyName)
}

Juzgamos de antemano si el evento actual se puede fusionar, y devolvemos falso si puede, y ya no ejecutamos el siguiente código, y luego ejecutamos nuestra propia función.

En este momento, podemos obtener el centro y el ojo correspondientes de la variable cameraLocations de data.js a través de la etiqueta de nodo correspondiente.

La animación de la cámara en movimiento utiliza  el   método moveCamera de  gv , que acepta 3 parámetros, ojo (cámara) , centro (objetivo) y animConfig (configuración de animación). Entonces volvemos a la animación actual   del  moveCameraAnim  propiedad de globalAnim que nos facilite a limpiar.

El siguiente paso es cambiar de página, lo que requiere mucho cuidado. Porque una vez que no se borra un determinado atributo, se producirán pérdidas de memoria y otros problemas, y el rendimiento será cada vez más lento. ¡Hará que la página se congele!

Por lo que necesitamos una función clearAction dedicada a borrar el modelo de datos  . Deberíamos poner todos los objetos de animación en un objeto o matriz. Esto es conveniente para limpiar al cambiar de página.

El pseudocódigo relevante es el siguiente:

/**
 * 清除动作
 */
clearAction(index) {
    var { dm, gv } = this
    var { g3d, d3d } = window

    allListener.mi3d && g3d.umi(allListener.mi3d)
    allListener.mi2d && gv.umi(allListener.mi2d)
    dm.removeScheduleTask(this.schedule)

    dm && dm.clear()
    d3d && d3d.clear()

    window.d3d = null
    window.dm = null

    for (var i in globalAnim) {
        globalAnim[i] && globalAnim[i].pause()
        globalAnim[i] = null
    }

    // 清除对应的 3D 图纸
    ht.Default.removeHTML(g3d)

    gv.addToDOM()
    ht.Default.xhrLoad(`displays/HT-project_2019/风电/${index}.json`, function (text) {
        let json = ht.Default.parse(text)
        gv.deserialize(json, function(json, dm2, gv2, datas) {
            if (json.title) document.title = json.title

            if (json.a['json.background']) {
                let bgJSON = json.a['json.background']
                if (bgJSON.indexOf('scenes') === 0) {
                    var bgG3d

                    if (g3d) {
                        bgG3d = g3d
                    } else {
                        bgG3d = new ht.graph3d.Graph3dView()
                    }

                    var bgG3dStyle = bgG3d.getView()
                    bgG3dStyle.className = index === 1 ? '' : index === 3 ? 'land' : 'offshore'

                    bgG3d.deserialize(bgJSON, function(json, dm3, gv3, datas) {
                        init3d(dm3, gv3)
                    })

                    bgG3d.addToDOM()
                    gv.addToDOM(bgG3dStyle)
                }
                gv.handleScroll = function () {}
            }

            init2d(dm2, gv2)
        })
    })
}

Primero, necesitamos  borrar dm (modelo de datos) gv (dibujo)  . También tenga en cuenta: mi (función de monitorización) , Schedule (tareas programadas)  debe  dm.clear ()  antes de  Eliminar . Todas las animaciones realizan la  operación stop ()  y luego establecen su valor en  nulo  . Cabe señalar aquí que  después de que se ejecute  la parada , la  función de devolución de llamada finishFunc se llamará una vez  .

Cuando nuestro dibujo 2D contiene un fondo 3D, necesitamos determinar si ya existe una instancia 3D y, si la hay, no es necesario que la creemos nuevamente. Interesado en conocer las   fugas de memoria de las aplicaciones webGL .

Al ingresar a dos escenas 3D, necesitamos una animación de apertura, como el gif al principio. Por lo tanto, debemos  guardar el centro  y el  ojo de las dos animaciones de apertura en las  ubicaciones de cámara  que hemos definido  .

offshoreStart, offshoreEnd, landStart y landEnd indican las posiciones inicial y final de las centrales eléctricas en tierra y en alta mar.

Necesitamos determinar si la carga actual es una planta de energía en alta mar o una planta de energía en tierra. Podemos agregar className al cargar el dibujo correspondiente  .

Hemos definido el parámetro de índice en la  función clearAction  . Si hace clic en una planta de energía terrestre, se pasa el número 3, y si es una planta de energía marina, es el número 4.

Por ejemplo, si necesito cargar una planta de energía terrestre, entonces puedo agregar  className juzgando  g3d.className = index === 3? 'Land': 'offshore'  .

Luego, realice el juicio de inicialización en init.

El pseudocódigo relevante es el siguiente:

function init() {
    var className = g3d.getView().className

    // 执行单独的事件
    this.selfAnimStart(className)

    this.initData()

    // 监听事件
    this.monitor()
}

Obtenemos el className correspondiente  , pasamos el tipo correspondiente y ejecutamos el evento de inicialización correspondiente,  y animamos la cámara a través de la función moveCameraAnim que hemos definido  .

El pseudocódigo relevante es el siguiente:

/**
  * 不同风电场的开场动画
  */
function selfAnimStart(type) {
    var gv = this.gv
    var { eye, center } = cameraLocations[`${type}End`]
    var config = {
            duration: 3000,
            eye,
            center,
         }

    this.moveCameraAnim(gv, config)
}

para resumir

Después de terminar este proyecto, obtuve mucho crecimiento y conocimientos. Una buena forma de lograr el rápido crecimiento de la tecnología es investigar constantemente los detalles. El proyecto es una obra de arte y debe pulirse continuamente hasta que esté satisfecho. Cada punto sutil afectará el rendimiento detrás. Por lo tanto, debemos hacer todo con el espíritu de un artesano.

Por supuesto, también espero que algunos socios puedan atreverse a explorar el campo de Internet industrial. Podemos lograr mucho más que esto. Esto requiere nuestra imaginación para agregar demostraciones más divertidas y prácticas a este campo. Y también aprender muchos conocimientos en el campo industrial.

Supongo que te gusta

Origin blog.csdn.net/iotopo/article/details/108193597
Recomendado
Clasificación