Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/webpack/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 服务器发送事件(SSE)在简单的3D多维数据集模型上使用Three.JS速度较慢_Javascript_Html_Three.js_Server Sent Events - Fatal编程技术网

Javascript 服务器发送事件(SSE)在简单的3D多维数据集模型上使用Three.JS速度较慢

Javascript 服务器发送事件(SSE)在简单的3D多维数据集模型上使用Three.JS速度较慢,javascript,html,three.js,server-sent-events,Javascript,Html,Three.js,Server Sent Events,我目前正在开发一个客户机-服务器应用程序,它使用SSE从数据中获取加速计数据,并将其传递到three.js模型,然后在浏览器上呈现结果 从技术上讲,应用程序应该只在浏览器上实时显示一个方向上的加速度计数据,因此延迟非常重要 由于我只传递一个数据(即,仅传递加速度计),因此该过程应快速且瞬时;但是,要将accX值传递给object.position.x甚至console.log(“加速度计x轴数据:+(传感器值/16384)),需要很长时间;偶尔显示一次数据。 有时,显示“WebGL场景”的整个浏

我目前正在开发一个客户机-服务器应用程序,它使用SSE从数据中获取加速计数据,并将其传递到three.js模型,然后在浏览器上呈现结果

从技术上讲,应用程序应该只在浏览器上实时显示一个方向上的加速度计数据,因此延迟非常重要

由于我只传递一个数据(即,仅传递加速度计),因此该过程应快速且瞬时;但是,要将accX值传递给object.position.x甚至console.log(“加速度计x轴数据:+(传感器值/16384)),需要很长时间;偶尔显示一次数据。 有时,显示“WebGL场景”的整个浏览器崩溃不会渲染,因为上下文丢失“错误和很长的“精度”错误。 到目前为止,我已经尝试了每一种方法,但我始终无法解决这个长期滞后的问题

这是我从服务器获得的,一个JSON文件,具有以下特定格式:

 "DMObjectsCompleteObject": [
        {
            "DataMapAddress": 1,
            "DataType": 9,
            "DefaultValue": 0,
            "Description": "Accelerometer X Axis Data",
            "MaxValue": 66,
            "MinValue": 18446744073709552000,
            "ReadOnly": false,
            "Value": -18706.4
        },
        {
            "DataMapAddress": 2,
            "DataType": 9,
            "DefaultValue": 0,
            "Description": "Accelerometer Y Axis Data",
            "MaxValue": 66,
            "MinValue": 18446744073709552000,
            "ReadOnly": false,
            "Value": 128
        }
]
这是我客户端的代码:

// Importing libraries and data
import * as THREE from "three";
if (!!window.EventSource) {
    var source = new EventSource("/sse");

    source.addEventListener('message', function (event) {
        // Parameters initialization
        const canvas = document.querySelector('#canvas');
        const accelPanel = document.querySelector('#accelPanel');
        const renderer = new THREE.WebGLRenderer({ canvas });
        const fov = 70;
        const aspect = 2;  // the canvas default
        const near = 20;
        const far = 500;

        // Initialize camera perspective
        const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);

        // The camera FOV when the model starts to move
        camera.position.z = 25;
        camera.up.set(0, 0, 1);
        camera.lookAt(0, 0, 0);

        // Add background grid and light
        const scene = new THREE.Scene();
        {
            const color = 0x00afaf;
            const intensity = 10;
            const light = new THREE.PointLight(color, intensity);
            scene.add(light);
        }

        // Make the 3D cube model with the XYZ axis
        const boxGeometry = new THREE.BoxGeometry();
        const boxMaterial = new THREE.MeshBasicMaterial({ color: "green", wireframe: false });
        const object = new THREE.Mesh(boxGeometry, boxMaterial);

        var cubeAxis = new THREE.AxesHelper(3);
        object.add(cubeAxis);

        object.scale.set(5, 5, 5)
        scene.add(object);
        scene.background = new THREE.Color(0.22, 0.23, 0.22);

        let currentIndex = 0
        let time = 0
        let velocity = new THREE.Vector3()
        requestAnimationFrame(render);

        // Rendering function responsible of creating the translation motion
        function render(dt) {
            dt *= 0.0001 // in seconds
            time += dt
            document.querySelector("#time").textContent = time.toFixed(2)


            // JSON.parse twice due to over-stringified string from SSE
            var obj = JSON.parse(JSON.parse(event.data));
            
            if (obj !== null) {
                // Sensor data
                if (
                    obj.hasOwnProperty("DataMapChangedObjectsAddressValue") &&
                    obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"] !==
                    undefined
                ) {
                    let sensorAddr =
                        obj["DataMapChangedObjectsAddressValue"][0]["DataMapAddress"];
                    let sensorValue =
                        obj["DataMapChangedObjectsAddressValue"][0]["Value"];

                    //Accelerometer X Axis
                    //if(sensorAddr === this.despToAddrMap.get("Accelerometer X Axis Data")){
                    if (sensorAddr === 1) {
                        // console.log(obj["DataMapChangedObjectsAddressValue"][2]["Value"])
                        console.log("Accelerometer X Axis Data: " + (sensorValue / 16384));
                    }

                    object.position.x = (sensorValue / 16384) * 500;
                    document.querySelector("#accX").textContent = (sensorValue / 16384) * 500;
                    object.rotation.y = -70.68;
                    var relativeCameraOffset = new THREE.Vector3(5, 10, 1);
                    var cameraOffset = relativeCameraOffset.applyMatrix4(object.matrixWorld);
                    camera.position.x = cameraOffset.x;
                    // camera.position.y = cameraOffset.y;
                    // camera.position.z = cameraOffset.z;
                    camera.lookAt(object.position);
                }
            }

            // // Find datapoint matching current time
            // while (data[currentIndex].time < time) {
            //     currentIndex++
            //     if (currentIndex >= data.length) return
            // }
            // const { rotX, rotY, rotZ, accX, accY, accZ } = data[currentIndex]
            // document.querySelector("#accX").textContent = accX;

            // const acceleration = new THREE.Vector3(accX, accY, accZ)
            // object.position.x = accX * 30;
            // object.rotation.y = -70.68;

            resizeToClient();
            renderer.render(scene, camera);
            requestAnimationFrame(render);
        }

        function resizeToClient() {
            const needResize = resizeRendererToDisplaySize()
            if (needResize) {
                const canvas = renderer.domElement;
                camera.aspect = canvas.clientWidth / canvas.clientHeight;
                camera.updateProjectionMatrix();
            }
        }

        function resizeRendererToDisplaySize() {
            const canvas = renderer.domElement;
            const width = canvas.clientWidth;
            const height = canvas.clientHeight;
            const needResize = canvas.width !== width || canvas.height !== height;
            if (needResize) {
                renderer.setSize(width, height, false);
            }
            return needResize;
        }
    }, false)

    source.addEventListener('open', function (e) {
        // document.getElementById('state').innerHTML = "Connected"
    }, false)

    source.addEventListener('error', function (e) {
        const id_state = document.getElementById('state')
        if (e.eventPhase == EventSource.CLOSED)
            source.close()
        if (e.target.readyState == EventSource.CLOSED) {
            id_state.innerHTML = "Disconnected"
        }
        else if (e.target.readyState == EventSource.CONNECTING) {
            id_state.innerHTML = "Connecting..."
        }
    }, false)
} else {
    console.log("Your browser doesn't support SSE")
}
//导入库和数据
从“三”中导入*作为三;
如果(!!window.EventSource){
var source=新事件源(“/sse”);
source.addEventListener('message',函数(事件){
//参数初始化
const canvas=document.querySelector(“#canvas”);
const accelPanel=document.querySelector(“#accelPanel”);
const renderer=new THREE.WebGLRenderer({canvas});
常数fov=70;
const aspect=2;//画布默认值
常数近=20;
常数far=500;
//初始化相机透视图
常量摄影机=新的三个透视摄影机(视野、方位、近距离、远距离);
//模型开始移动时的摄影机视野
摄像机位置z=25;
摄像机设置(0,0,1);
摄像机。注视(0,0,0);
//添加背景网格和灯光
const scene=new THREE.scene();
{
const color=0x00afaf;
常数强度=10;
恒光=新的三点光(颜色、强度);
场景。添加(灯光);
}
//使用XYZ轴创建三维立方体模型
const boxGeometry=new THREE.boxGeometry();
const-boxMaterial=new THREE.MeshBasicMaterial({颜色:“绿色”,线框:false});
const object=new THREE.Mesh(boxGeometry,boxMaterial);
var cubeAxis=新的三轴轴承(3);
object.add(cubeAxis);
对象。比例。设置(5,5,5)
场景。添加(对象);
scene.background=新的三种颜色(0.22,0.23,0.22);
设currentIndex=0
让时间=0
设速度=新的3.Vector3()
请求动画帧(渲染);
//负责创建平移运动的渲染函数
函数渲染(dt){
dt*=0.0001//以秒为单位
时间+=dt
document.querySelector(“#time”).textContent=time.toFixed(2)
//由于来自SSE的字符串过度字符串化,JSON.parse出现两次
var obj=JSON.parse(JSON.parse(event.data));
如果(对象!==null){
//传感器数据
如果(
对象hasOwnProperty(“DataMapChangedObjectsAddressValue”)&&
obj[“DataMapChangedObjectsAddressValue”][0][“DataMapAddress”]==
未定义
) {
让我们加入=
obj[“DataMapChangedObjectsAddressValue”][0][“DataMapAddress”];
让传感器测量值=
obj[“DataMapChangedObjectsAddressValue”][0][“Value”];
//加速度计X轴
//if(sensorAddr==this.despToAddrMap.get(“加速度计X轴数据”)){
如果(传感器地址===1){
//console.log(obj[“DataMapChangedObjectsAddressValue”][2][“Value”])
console.log(“加速计X轴数据:”+(sensorValue/16384));
}
object.position.x=(sensorValue/16384)*500;
document.querySelector(“#accX”).textContent=(sensorValue/16384)*500;
object.rotation.y=-70.68;
var relativeCameraOffset=新的三个向量3(5,10,1);
var cameraOffset=relativeCameraOffset.applyMatrix4(object.matrixWorld);
camera.position.x=cameraOffset.x;
//camera.position.y=cameraOffset.y;
//camera.position.z=cameraOffset.z;
摄像机。注视(物体。位置);
}
}
////查找与当前时间匹配的数据点
//while(数据[currentIndex]。时间<时间){
//当前索引++
//如果(currentIndex>=data.length)返回
// }
//const{rotX,rotY,rotZ,accX,accY,accZ}=data[currentIndex]
//document.querySelector(“#accX”).textContent=accX;
//常数加速度=新的三个矢量3(accX、accY、accZ)
//object.position.x=accX*30;
//object.rotation.y=-70.68;
resizeToClient();
渲染器。渲染(场景、摄影机);
请求动画帧(渲染);
}
函数resilizetoclient(){
const needResize=resizeRendererToDisplaySize()
如果(需要调整大小){
const canvas=renderer.domeElement;
camera.aspect=canvas.clientWidth/canvas.clientHeight;
camera.updateProjectMatrix();
}
}
函数resizeRenderToDisplaySize(){
const canvas=renderer.domeElement;
const width=canvas.clientWidth;
常数高度=canvas.clientHeight;
const needResize=canvas.width!==width | | canvas.height!==height;
source.addEventListener('message', function (event) {
console.log(event)
}
'use strict';

const util = require('util');
// const config = require('../lib/config');
const requireAuthorization = require('../middlewares/requireAuthorization');
const router = require('express').Router();
// const thinky = require('../lib/thinky');
// const r = thinky.r;
// const Errors = thinky.Errors;
const logger = require('../lib/logger');
const helpers = require('../lib/helpers');

// redis feed for events

const subscriber = require('../lib/redis').createClient();
const EventEmitter = require('events');
const spine = new EventEmitter();
subscriber.on('message', function (channel, message) {
  spine.emit(channel, message);
});

// setInterval(function () {
//   spine.emit('scubamailer_feed', JSON.stringify({time: Date.now()}));
// }, 500);

subscriber.subscribe('scubamailer_feed');


router.use(requireAuthorization);

router.get('/subscribe', function (req, res, next) {

  // Good read -
  // https://learn.javascript.ru/server-sent-events#tipy-sobytiy
  // https://www.terlici.com/2015/12/04/realtime-node-expressjs-with-sse.html
  // http://stackoverflow.com/questions/27898622/server-sent-events-stopped-work-after-enabling-ssl-on-proxy
  // http://stackoverflow.com/a/33414096/1885921
  // https://github.com/expressjs/compression/issues/17

  // how to remove listeners
  // https://odetocode.com/blogs/scott/archive/2013/07/16/angularjs-listening-for-destroy.aspx

  logger.info('User %s subscribed to event feed from IP %s.', req.user.email, helpers.extractIPfromReq(req), {
    user: req.user.email,
    type: 'user/unsubFromEvents'
  });

  req.isSSE = true; // PLEASE, DO NOT TOUCH IT, OK???
  req.socket.setTimeout(24 * 60 * 60 * 1000);
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.setHeader('X-Accel-Buffering', 'no');

  // redis feed events
  const listen = function (message) {
    res.write(util.format('event: notification\ndata: %s\n\n', message));
    // res.flush(); // https://github.com/expressjs/compression#server-sent-events
  };
  const tickerInterval = setInterval(function () {
    res.write(util.format('event: time\ndata: %s\n\n', Date.now()));
  }, 500);


  const stopListening = function () {
    logger.info('User %s [%s] unsubscribed from event feed...', req.user.email, helpers.extractIPfromReq(req), {
      user: req.user.email,
      type: 'user/unsubFromEvents'
    });
    clearInterval(tickerInterval);
    spine.removeListener('scubamailer_feed', listen);
  };
  res.once('close', stopListening);
  res.once('finish', stopListening);
  spine.on('scubamailer_feed', listen);


  const entitiesToMonitor = [
    'Campaign',
    'EmailImport',
    'EmailExport',
    'User',
    'Server'
  ];

  return Promise.all(entitiesToMonitor.map(function (entity) {
    return req.model[entity].changes()
      .then(function (feed) {
        feed.each(function (error, doc) {
          if (error) {
            throw error;
          }
          if (doc.isSaved()) { // send updates only if document is persisted in database
            if (entity === 'User') {
              res.write(util.format('event: %s\ndata: %s\n\n', entity, JSON.stringify(doc.formatToJSON())));
            } else {
              res.write(util.format('event: %s\ndata: %s\n\n', entity, JSON.stringify(doc)));
            }

            // res.flush(); // https://github.com/expressjs/compression#server-sent-events
          }
        });
        return Promise.resolve();
      });
  }))
    .catch(next);
});

module.exports = exports = router;

  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');
  res.setHeader('X-Accel-Buffering', 'no');