From 09d89a8001713d8288f818243a0b88e5bb076f1b Mon Sep 17 00:00:00 2001 From: bigint405 Date: Sun, 17 Jan 2021 12:19:29 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=8A=BD=E5=8F=96=E5=AF=BC=E8=A7=88?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/app.js | 34 +++---- src/controls/CameraTween.js | 3 - src/manager/XRPlayerManager.js | 165 ++++++++++++++++++++++++++++----- 3 files changed, 151 insertions(+), 51 deletions(-) diff --git a/example/src/app.js b/example/src/app.js index 0d36e90..407b802 100644 --- a/example/src/app.js +++ b/example/src/app.js @@ -49,7 +49,7 @@ class App extends React.Component { this.xrManager.setFovVerticalScope(0, 180); this.xrManager.enableKeyControl(true); this.xrManager.enableChangeFov(true); - this.xrManager.cameraTweenGroup.enableAutoNext(true); + this.xrManager.playingCameraTweenGroup.enableAutoNext(true); // this.onCameraAnimationSet(); } @@ -70,10 +70,10 @@ class App extends React.Component { } ] var cameraTweenGroup = this.xrManager.createCameraTweenGroup(animateList, true); - //cameraTweenGroup.enableAutoNext(true); + //playingCameraTweenGroup.enableAutoNext(true); this.xrManager.setCameraTweenGroup(cameraTweenGroup); // this.xrManager.onCameraAnimationEnded = (index) => { - // cameraTweenGroup.next(); + // playingCameraTweenGroup.next(); // } } @@ -327,32 +327,18 @@ class App extends React.Component { } onPickDirector = () => { - let pos = this.xrManager.getCameraLatLon(); - let fov = this.xrManager.getCameraFov(); - let startLat = 90, startLon = 180; - if (this.autoDisplayList.length !== 0) { - startLat = this.autoDisplayList[this.autoDisplayList.length - 1].end.lat; - startLon = this.autoDisplayList[this.autoDisplayList.length - 1].end.lon; - } - this.autoDisplayList.push({ - start: { lat: startLat, lon: startLon, fov: 80, distance: 500 }, - end: { lat: pos.lat, lon: pos.lon, fov: fov, distance: 500 }, - duration: 5000, easing: TWEEN.Easing.Sinusoidal.InOut, - }) + this.xrManager.pickDirector('name'); } onStartAutoDisplay = () => { - var cameraTweenGroup = this.xrManager.createCameraTweenGroup(this.autoDisplayList, true); - this.xrManager.setCameraTweenGroup(cameraTweenGroup); - cameraTweenGroup.enableAutoNext(true); - this.xrManager.startCameraTweenGroup(); + this.xrManager.createDemonstrateCameraTween() } debugFunc = () => { - let videoBox = this.boxManager.getEmbeddedBox('box3'); - console.log(videoBox.getPosition()) + console.log(this.xrManager.getDirectorNames()); } + render() { return (
@@ -408,12 +394,14 @@ class App extends React.Component { + + + + - -
diff --git a/src/controls/CameraTween.js b/src/controls/CameraTween.js index fafe7a7..fbc8d26 100644 --- a/src/controls/CameraTween.js +++ b/src/controls/CameraTween.js @@ -20,9 +20,6 @@ class CameraTween { this.reset = cameraControl.initSphericalData; //动画结束后视角停在结束的位置,不会回到之前的位置 this.started = false; //在start之后stop之前调用start会导致不会调用onStop,无法使用相机控制 - this.startTime = 0; - this.endTime = 0; - this.posType = 0; // 0 表示都不用, 1 采用xyz, 2 采用经纬度 this.fovChange = false; //是否涉及fov的改变 this.disChange = false; //是否涉及distance的改变 diff --git a/src/manager/XRPlayerManager.js b/src/manager/XRPlayerManager.js index 3500b3c..55fdd7c 100644 --- a/src/manager/XRPlayerManager.js +++ b/src/manager/XRPlayerManager.js @@ -39,6 +39,7 @@ class XRPlayerManager { this.handler = handler; this.scene = null; + this.radius = null; this.sceneMesh = null; this.camera = null; this.renderer = null; @@ -46,7 +47,6 @@ class XRPlayerManager { this.sceneContainer = null; // 全景背景挂载节点 this.sceneTextureHelper = null; //全景场景纹理加载控制器 - this.innerViewControls = null; this.spriteShapeHelper = null; this.spriteParticleHelper = null; // 粒子展示 @@ -68,7 +68,9 @@ class XRPlayerManager { num: 0, paused: false }; - this.cameraTweenGroup = null; + this.playingCameraTweenGroup = null; + this.creatingDirectors = []; + this.directorDurations = []; this.onCameraAnimationEnded = null; @@ -111,6 +113,7 @@ class XRPlayerManager { axes_helper_display: isAxesHelperDisplay, } = this.props; const { panoramic_type = '360', radius = 500, height = 1000 } = textureResource; + this.radius = radius; this.sceneContainer = document.getElementById('video'); let geometry; if (panoramic_type === '180') { @@ -463,9 +466,9 @@ class XRPlayerManager { /** * @function * @name XRPlayerManager#moveCameraTo - * @param {*} descPos 相机目标位置,采用lat,lon表示 + * @param {*} endPos 相机目标位置,采用lat,lon表示 * @param {function} onStart 移动开始事件回调 - * @param {functon} onEnd 移动结束事件回调 + * @param {function} onEnd 移动结束事件回调 * @param {number} duration 相机移动动画的持续时长 * @param {number} delay 相机动画延迟启动时长 */ @@ -622,7 +625,7 @@ class XRPlayerManager { simpleCreateTextBox = (boxId) => { //在相机聚焦位置创建一个初始文本框 let textBox = new EmbeddedTextBox(boxId); textBox.setText('简易文本框'); - let position = this.getCameraPosition().clone().normalize().multiplyScalar(-500); + let position = this.getCameraPosition().clone().normalize().multiplyScalar(-this.radius); const spherical = new THREE.Spherical(); spherical.setFromCartesianCoords(position.x, position.y, position.z); let phi = spherical.phi; @@ -635,7 +638,7 @@ class XRPlayerManager { simpleCreateImageBox = (boxId) => { //在相机聚焦位置创建一个初始图片框 let textBox = new EmbeddedImageBox(boxId); - let position = this.getCameraPosition().clone().normalize().multiplyScalar(-500); + let position = this.getCameraPosition().clone().normalize().multiplyScalar(-this.radius); const spherical = new THREE.Spherical(); spherical.setFromCartesianCoords(position.x, position.y, position.z); let phi = spherical.phi; @@ -648,7 +651,7 @@ class XRPlayerManager { simpleCreateVideoBox = (boxId) => { //在相机聚焦位置创建一个初始视频框 let textBox = new EmbeddedVideoBox(boxId); - let position = this.getCameraPosition().clone().normalize().multiplyScalar(-500); + let position = this.getCameraPosition().clone().normalize().multiplyScalar(-this.radius); const spherical = new THREE.Spherical(); spherical.setFromCartesianCoords(position.x, position.y, position.z); let phi = spherical.phi; @@ -810,18 +813,21 @@ class XRPlayerManager { 2. stop或自动结束之后再调用start重播 params的格式: { - pos0, pos1, duration, 必需 + start, end, duration, 必需 easing, callback 非必需(easing是速度变化的方式,详见https://www.createjs.com/docs/tweenjs/classes/Ease.html) } - pos0、pos1的格式 + start、end的格式 { lat, lon, 必需 - fov 非必需 + fov, 非必需 + distance 非必需 }或 { x, y, z, 必需 - fov 非必需 + fov, 非必需 + distance 非必需 } + 可加入自定义的变量,并通过设置onUpdate使用这些变量 */ getCameraAnimationList = () => { if (this.senceConfig && this.senceConfig.hasOwnProperty('auto_guide_list')) { @@ -841,7 +847,7 @@ class XRPlayerManager { cameraTweens.push(animation); }); var cameraTweenGroup = new CameraTweenGroup(cameraTweens, - 500, this.innerViewControls); + this.radius, this.innerViewControls); cameraTweenGroup.onCameraAnimationEnded = (key) => { this.onCameraAnimationEnded && this.onCameraAnimationEnded(key); @@ -855,59 +861,168 @@ class XRPlayerManager { this.onCameraAnimationStop && this.onCameraAnimationStop(key); } - this.cameraTweenGroup = cameraTweenGroup; + this.playingCameraTweenGroup = cameraTweenGroup; return cameraTweenGroup; } createCameraAnimation = (params) => { - var cameraTween = new CameraTween(params, this.camera, 500, + var cameraTween = new CameraTween(params, this.camera, this.radius, this.innerViewControls, this.cameraTweenStatus); cameraTween.key = params.key; return cameraTween; } setCameraTweenGroup = (cameraTweenGroup) => { - this.cameraTweenGroup = cameraTweenGroup; + this.playingCameraTweenGroup = cameraTweenGroup; } getCameraTweenGroup = () => { - return this.cameraTweenGroup; + return this.playingCameraTweenGroup; } startCameraTweenGroup = (time) => { - if (!this.cameraTweenGroup) { + if (!this.playingCameraTweenGroup) { return; } if (!!!time) { - this.cameraTweenGroup.start(); + this.playingCameraTweenGroup.start(); } else { - this.cameraTweenGroup.start(time); + this.playingCameraTweenGroup.start(time); } } stopCameraTweenGroup = () => { - this.cameraTweenGroup && this.cameraTweenGroup.stop(); + this.playingCameraTweenGroup && this.playingCameraTweenGroup.stop(); } pauseCameraTweenGroup = () => { - this.cameraTweenGroup && this.cameraTweenGroup.pause(); + this.playingCameraTweenGroup && this.playingCameraTweenGroup.pause(); } playCameraTweenGroup = () => { - this.cameraTweenGroup && this.cameraTweenGroup.play(); + this.playingCameraTweenGroup && this.playingCameraTweenGroup.play(); } nextCameraTween = () => { - this.cameraTweenGroup && this.cameraTweenGroup.next(); + this.playingCameraTweenGroup && this.playingCameraTweenGroup.next(); } enableCameraTweenGroupAutoNext = (enable) => { - this.cameraTweenGroup.enableAutoNext(enable); + this.playingCameraTweenGroup.enableAutoNext(enable); } enableCameraTweenGroupLoop = (enable) => { - this.cameraTweenGroup.enableLoop(enable); + this.playingCameraTweenGroup.enableLoop(enable); + } + + /****************************相机动画接口对接***********************************/ + /** + * @description 选取当前位置为新的导览点并命名,并选择和上一个导览点的时间差(第一个点可忽略) + */ + pickDirector = (name, duration=5000) => { + let pos = this.getCameraLatLon(); + let fov = this.getCameraFov(); + this.creatingDirectors.push({lat: pos.lat, lon: pos.lon, fov: fov, distance: this.radius, name: name}); + this.directorDurations.push(duration); + } + + /** + * @description 根据序号设置之前的导览点(从0开始),成功返回0,序号越界返回-1。 + * @param {int} index 序号 + * @param {Object} params 目标样式,包含lat, lon, fov, distance, name,不变的话可以不加进去 + */ + setDirector = (index, params) => { + if (index >= this.creatingDirectors.length) { + return -1;//序号越界 + } + Object.assign(this.creatingDirectors[index], params); + return 0; + } + + /** + * @description 返回导览点名字的序列 + */ + getDirectorNames = () => { + let names = []; + if (!!!this.playingCameraTweenGroup) { + return names; + } + this.playingCameraTweenGroup.cameraTweens.forEach((cameraTween) => { + let name = null; + if (cameraTween.pos0.hasOwnProperty('name')) { + name = cameraTween.pos0.name; + } + names.push(name); + }); + const l = this.playingCameraTweenGroup.cameraTweens.length; + if (l > 1) { + let name = null; + if (this.playingCameraTweenGroup.cameraTweens[l - 1].pos0.hasOwnProperty('name')) { + name = this.playingCameraTweenGroup.cameraTweens[l - 1].pos0.name; + } + names.push(name); + } + return names; + } + + /** + * @description 根据序号删除指定导览点,成功返回0,序号越界返回-1。 + * @param {int} index 序号 + */ + deleteDirector = (index) => { + if (index >= this.creatingDirectors.length) { + return -1;//序号越界 + } + this.creatingDirectors.splice(index, 1); + this.directorDurations.splice(index, 1); + return 0; + } + + /** + * @description 清空所有导览点。 + */ + clearDirector = () => { + this.creatingDirectors = []; + return 0; + } + + /** + * @description 根据当前选择的点创建演示序列。 + */ + createDemonstrateCameraTween = () => { + let tweenList = []; + if (this.creatingDirectors.length === 0) {//没有点 + this.playingCameraTweenGroup = null; + return; + } + else if (this.creatingDirectors.length === 1) {//只有一个点 + let oldPos = {}, newPos = {}; + Object.assign(oldPos, this.creatingDirectors[0]); + Object.assign(newPos, this.creatingDirectors[0]); + tweenList.push(this.createCameraAnimation({ + start: oldPos, + end: newPos, + duration: 1, + easing: "InOut" + })); + } + else {//有多个点 + for (let i = 1; i < this.creatingDirectors.length; i++) + { + let oldPos = {}, newPos = {}; + Object.assign(oldPos, this.creatingDirectors[i - 1]); + Object.assign(newPos, this.creatingDirectors[i]); + tweenList.push(this.createCameraAnimation({ + start: oldPos, + end: newPos, + duration: this.directorDurations[i], + easing: "InOut" + })); + } + } + this.playingCameraTweenGroup = new CameraTweenGroup(tweenList, + this.radius, this.innerViewControls); } /** From b11be1bd7822749af0db2d05e27fd9d085c2260a Mon Sep 17 00:00:00 2001 From: bigint405 Date: Tue, 19 Jan 2021 12:36:59 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=88=A9=E7=94=A8=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E5=88=9D=E6=AD=A5=E6=9B=B4=E6=94=B9=E4=B9=8B?= =?UTF-8?q?=E5=89=8D=E7=9A=84=E6=A0=87=E7=AD=BE=E4=BA=8B=E4=BB=B6=E3=80=81?= =?UTF-8?q?=E5=AF=BC=E8=A7=88=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/app.js | 12 +- public/mock/view1.json | 233 +++++++++++++++++++------------ src/Player.js | 4 + src/controls/CameraTween.js | 14 ++ src/display/SpriteShapeHelper.js | 48 ++++++- src/event/EventBus.js | 2 +- src/event/Events.js | 5 +- src/manager/XRPlayerManager.js | 30 +--- 8 files changed, 225 insertions(+), 123 deletions(-) diff --git a/example/src/app.js b/example/src/app.js index 407b802..b832793 100644 --- a/example/src/app.js +++ b/example/src/app.js @@ -6,6 +6,9 @@ import * as THREE from 'three'; import EmbeddedTextBox from "../../src/display/ResourceBox/EmbeddedResource/EmbeddedTextBox"; import EmbeddedImageBox from "../../src/display/ResourceBox/EmbeddedResource/EmbeddedImageBox"; import EmbeddedVideoBox from "../../src/display/ResourceBox/EmbeddedResource/EmbeddedVideoBox"; +import EventBus from "../../src/event/EventBus"; +import Events from "../../src/event/Events"; + class App extends React.Component { state = { @@ -335,7 +338,14 @@ class App extends React.Component { } debugFunc = () => { - console.log(this.xrManager.getDirectorNames()); + EventBus.trigger(Events.EVENT_POP_EFFECT_PANEL, { + name: "image", + props: {data:{ + type: "image", + imageUrl: "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", + jumpUrl: "http://www.youmuvideo.com" + }} + }); } diff --git a/public/mock/view1.json b/public/mock/view1.json index 79bafec..4ba558c 100644 --- a/public/mock/view1.json +++ b/public/mock/view1.json @@ -24,9 +24,9 @@ ] ], "hot_spot_list": [ - [ - "zhong_shan_she_qu", - { + { + "key": "zhong_shan_she_qu", + "props": { "lat": 140, "lon": -40, "position": "top", @@ -37,11 +37,24 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/zhong_shan_she_qu.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "image", + "props": { + "data": { + "type": "image", + "imageUrl": "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", + "jumpUrl": "http://www.youmuvideo.com" + } + } + } } - ], - [ - "zhong_shan_ji_nian_tang", - { + }, + { + "key": "zhong_shan_ji_nian_tang", + "props": { "lat": 310, "lon": -60, "animate": true, @@ -51,11 +64,23 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/zhong_shan_ji_nian_tang.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "video", + "props": { + "data": { + "type": "video", + "videoUrl": "https://video-cloud-bupt.oss-cn-beijing.aliyuncs.com/hangzhou.mp4" + } + } + } } - ], - [ - "ling_ze_xu", - { + }, + { + "key": "ling_ze_xu", + "props": { "lat": 305, "lon": 55, "animate": true, @@ -66,11 +91,23 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/lin_ze_xu_chu_sheng_di.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "infocard", + "props": { + "data": { + "type": "infocard", + "iframeUrl": "https://gs.ctrip.com/html5/you/place/14.html" + } + } + } } - ], - [ - "ma_qiu_chang", - { + }, + { + "key": "ma_qiu_chang", + "props": { "lat": 320, "lon": 20, "animate": true, @@ -80,11 +117,30 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/tang_dai_ma_qiu_chang_yi_zhi.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } + } + } } - ], - [ - "ren_shou_tang", - { + }, + { + "key": "ren_shou_tang", + "props": { "lat": 360, "lon": 20, "animate": true, @@ -94,11 +150,30 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } + } + } } - ], - [ - "ou_ye_chi", - { + }, + { + "key": "ou_ye_chi", + "props": { "lat": 410, "lon": 40, "animate": true, @@ -109,74 +184,27 @@ "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ou_ye_chi_yi_zhi.jpg", "img_height": 100, "img_width": 150 + }, + "event": { + "type": "event_pop_effect_panel", + "props": { + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } + } + } } - ] - ], - "event_list": [ - [ - "zhong_shan_she_qu", - { - "type": "image", - "imageUrl": "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", - "jumpUrl": "http://www.youmuvideo.com" - } - ], - [ - "zhong_shan_ji_nian_tang", - { - "type": "video", - "videoUrl": "https://video-cloud-bupt.oss-cn-beijing.aliyuncs.com/hangzhou.mp4" - } - ], - [ - "ling_ze_xu", - { - "type": "infocard", - "iframeUrl": "https://gs.ctrip.com/html5/you/place/14.html" - } - ], - [ - "ma_qiu_chang", - { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true - } - ], - [ - "ou_ye_chi", - { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true - } - ], - [ - "ren_shou_tang", - { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true - } - ] + } ], "particle_effect": { "url": "https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/sprites/snowflake1.png", @@ -189,26 +217,41 @@ { "key": "zhong_shan_ji_nian_tang", "start": { + "name": "zhong_shan_ji_nian_tang", "lat": 90, "lon": -15, "fov": 90 }, "end": { + "name": "ling_ze_xu", "lat": 69, "lon": 110, "fov": 58 }, "duration": 5000, - "easing": "InOut" + "easing": "InOut", + "complete_event": { + "type": "event_pop_effect_panel", + "props": { + "name": "image", + "props": {"data":{ + "type": "image", + "imageUrl": "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", + "jumpUrl": "http://www.youmuvideo.com" + }} + } + } }, { "key": "ling_ze_xu", "start": { + "name": "ling_ze_xu", "lat": 69, "lon": 110, "fov": 58 }, "end": { + "name": "ma_qiu_chang", "lat": 105, "lon": 110, "fov": 58 @@ -219,11 +262,13 @@ { "key": "ma_qiu_chang", "start": { + "name": "ma_qiu_chang", "lat": 105, "lon": 110, "fov": 58 }, "end": { + "name": "ren_shou_tang", "lat": 100, "lon": 137, "fov": 38 @@ -234,11 +279,13 @@ { "key": "ren_shou_tang", "start": { + "name": "ren_shou_tang", "lat": 100, "lon": 137, "fov": 38 }, "end": { + "name": "ou_ye_chi", "lat": 100, "lon": 180, "fov": 70 @@ -249,11 +296,13 @@ { "key": "ou_ye_chi", "start": { + "name": "ou_ye_chi", "lat": 100, "lon": 180, "fov": 70 }, "end": { + "name": "zhong_shan_she_qu", "lat": 91.5, "lon": 206, "fov": 80 @@ -264,11 +313,13 @@ { "key": "zhong_shan_she_qu", "start": { + "name": "zhong_shan_she_qu", "lat": 91.5, "lon": 206, "fov": 80 }, "end": { + "name": "end", "lat": 90, "lon": -15, "fov": 90 diff --git a/src/Player.js b/src/Player.js index 4804a68..c214edc 100644 --- a/src/Player.js +++ b/src/Player.js @@ -91,6 +91,10 @@ class XRPlayer extends Component { let result = this.props.onEventHandler(props.type, props); if (result) return; }, this); + //注册弹窗事件 + EventBus.on(Events.EVENT_POP_EFFECT_PANEL, (props) => { + this.eventHandler(props.name, props.props, props.callback); + }, this); window.addEventListener('resize', this.onWindowResize, false); } diff --git a/src/controls/CameraTween.js b/src/controls/CameraTween.js index fbc8d26..dfaad2e 100644 --- a/src/controls/CameraTween.js +++ b/src/controls/CameraTween.js @@ -1,5 +1,7 @@ import * as THREE from 'three'; import TWEEN from '@tweenjs/tween.js'; +import EventBus from "../event/EventBus"; +import Events from "../event/Events"; class CameraTween { constructor(tweenParams, camera, cameraDistance, cameraControl) { @@ -27,6 +29,9 @@ class CameraTween { this.onCameraAnimationEnded = null; // 动画结束后回调 this.onCameraAnimationStop = null; this.onCameraAnimationStart = null; + + this.completeEventParams = null; + this.init(tweenParams); } @@ -35,6 +40,8 @@ class CameraTween { this.easing = params.easing; this.pos0 = {}; this.pos1 = {}; + this.completeEventParams = {}; + Object.assign(this.completeEventParams, params.complete_event) Object.assign(this.pos0, params.start); Object.assign(this.pos1, params.end); this.tween = new TWEEN.Tween(this.pos0).to(this.pos1, params.duration); @@ -49,6 +56,9 @@ class CameraTween { this.onCameraAnimationEnded(this.key); this.reset(); this.started = false; + if (this.completeEventParams.type && this.completeEventParams.props) { + EventBus.trigger(this.completeEventParams.type, this.completeEventParams.props); + } }); this.tween.onStop(() => { this.onCameraAnimationStop && @@ -101,6 +111,10 @@ class CameraTween { }); } + setCompleteEvent = (params) => { + this.completeEventParams = params; + } + setFocus = (focus) => { this.focus.x = focus.x; this.focus.y = focus.y; diff --git a/src/display/SpriteShapeHelper.js b/src/display/SpriteShapeHelper.js index a279d6a..dd558cc 100644 --- a/src/display/SpriteShapeHelper.js +++ b/src/display/SpriteShapeHelper.js @@ -4,6 +4,7 @@ import * as THREE from 'three'; import { Radius } from '../const/PanoConst'; import TWEEN from '@tweenjs/tween.js'; +import EventBus from "../event/EventBus"; class SpriteShapeHelper { @@ -16,11 +17,31 @@ class SpriteShapeHelper { this.hotSpotMap = null; // 热点标签数据 this.hotSpotMeshMap = null; // 热点标签Mesh Map,便于动态缩减 this.pointGroup = null; // 场景中的热点组合 + this.eventMap = null; // 热点事件 this.objectClickHandler = null; this.tagClickHandler = null; this.isTipVisible = true; this.hotSpotClickable = true; + + this.initHandler(); + } + + initHandler = () => { + this.objectClickHandler = (intersects) => { + const key = intersects[0].object.name; + if (this.eventMap && this.eventMap.has(key)) { + const data = this.eventMap.get(key); + EventBus.trigger(data.type, data.props); + } + }; + this.tagClickHandler = (key) => { + if (this.eventMap && this.eventMap.has(key)) { + const data = this.eventMap.get(key); + console.log(data) + EventBus.trigger(data.type, data.props); + } + } } setIsTipVisible = (enable) => { @@ -63,12 +84,23 @@ class SpriteShapeHelper { setHotSpotList = (hot_spot_list) => { this.resetHotSpotGroup(); - this.hotSpotMap = new Map(hot_spot_list); + this.hotSpotMap = new Map(); + this.eventMap = new Map(); + hot_spot_list.forEach((spot) => { + this.hotSpotMap.set(spot.key, spot.props); + this.eventMap.set(spot.key, spot.event); + }); this.hotSpotMap.forEach((value, key) => { this.createPoint(key, value) }); } + setEventList = (eventList) => { + this.eventMap = new Map(eventList); + console.log('event_map') + console.log(this.eventMap) + } + addHotSpot = (hot_spot) => { if (!this.pointGroup) { this.resetHotSpotGroup(); @@ -76,6 +108,12 @@ class SpriteShapeHelper { this.createPoint(hot_spot.key, hot_spot.value) } + addEvent = (event) => { + if (event && !this.eventMap.has(event.key)) { + this.eventMap.set(event.key, event.value); + } + } + /** * 清空场景中的所有热点标签 */ @@ -98,7 +136,7 @@ class SpriteShapeHelper { } } - contertSph2Rect = (lat, lon) => { + convertSph2Rect = (lat, lon) => { let r = Radius; const phi = THREE.Math.degToRad(lat); const theta = THREE.Math.degToRad(lon); @@ -113,7 +151,7 @@ class SpriteShapeHelper { let { lat, lon, res_url, opacity = 1, scale = 16, animate = false, title = null, img_url = null, img_height = 100, img_width = 100, title_width } = value; - let position = this.contertSph2Rect(lat, lon); + let position = this.convertSph2Rect(lat, lon); let meshGroup = new THREE.Group(); meshGroup.name = key; meshGroup.position.set(...position); @@ -309,12 +347,12 @@ class SpriteShapeHelper { const container = document.getElementById('xr-container') container.addEventListener('click', (event) => { event.preventDefault(); - console.log('检测热点点击'); + // console.log('检测热点点击'); var intersects = this.getIntersects(event); //如果只需要将第一个触发事件,那就取数组的第一个模型 if (intersects.length > 0) { if (this.objectClickHandler) { - console.log('intersects', intersects); + // console.log('intersects', intersects); this.objectClickHandler(intersects); } } diff --git a/src/event/EventBus.js b/src/event/EventBus.js index cda786e..4883cdc 100644 --- a/src/event/EventBus.js +++ b/src/event/EventBus.js @@ -96,7 +96,7 @@ class EventBus { if (payload.hasOwnProperty('type')) throw new Error('\'type\' is a reserved word for event dispatching'); - payload.type = type; + // payload.type = type; this.handlers[type] = this.handlers[type].filter((item) => item); this.handlers[type].forEach(handler => handler && handler.callback.call(handler.scope, payload)); diff --git a/src/event/Events.js b/src/event/Events.js index 019e33f..59c9626 100644 --- a/src/event/Events.js +++ b/src/event/Events.js @@ -3,7 +3,8 @@ */ const EVENT_SENCE_RES_READY = 'event_sence_res_ready'; //全景背景资源准备完成 - +const EVENT_POP_EFFECT_PANEL = 'event_pop_effect_panel'; //弹出弹窗 export default { - EVENT_SENCE_RES_READY + EVENT_SENCE_RES_READY, + EVENT_POP_EFFECT_PANEL }; diff --git a/src/manager/XRPlayerManager.js b/src/manager/XRPlayerManager.js index 55fdd7c..a54a7fb 100644 --- a/src/manager/XRPlayerManager.js +++ b/src/manager/XRPlayerManager.js @@ -225,9 +225,8 @@ class XRPlayerManager { if (config.hasOwnProperty('muted')) { this.setGlobalMuted(config.muted); } - if (config.hasOwnProperty('hot_spot_list') - && config.hasOwnProperty('event_list')) { - this.setHotSpots(config.hot_spot_list, config.event_list); + if (config.hasOwnProperty('hot_spot_list')) { + this.setHotSpots(config.hot_spot_list); } if (config.hasOwnProperty('particle_effect')) { this.setParticleEffectRes(config.particle_effect); @@ -350,36 +349,21 @@ class XRPlayerManager { /****************************热点标签相关控制接口************************* */ resetHotSpotsData = () => { if (!this.spriteShapeHelper) { - this.spriteEventList = new Map(); this.spriteShapeHelper = new SpriteShapeHelper(this.scene, this.camera, this.renderer, this.mount); } else { - this.spriteEventList.clear(); + this.spriteShapeHelper.resetHotSpotGroup(); } } - setHotSpots = (hot_spot_list, event_list) => { + setHotSpots = (hot_spot_list) => { this.resetHotSpotsData(); - this.spriteEventList = new Map(event_list); this.spriteShapeHelper.setHotSpotList(hot_spot_list); - this.spriteShapeHelper.objectClickHandler = (intersects) => { - const key = intersects[0].object.name; - this.emitEvent(key, () => { - this.closeEffectContainer(); - }) - } - this.spriteShapeHelper.tagClickHandler = (key) => { - this.emitEvent(key, () => { - this.closeEffectContainer(); - }) - } } addHotSpot = (hot_spot, event) => { this.spriteShapeHelper.addHotSpot(hot_spot); - if (event != null && !this.spriteEventList.has(event.key)) { - this.spriteEventList.set(event.key, event.value); - } + this.spriteShapeHelper.addEvent(event); } removeHotSpot = (hot_spot_key) => { @@ -958,8 +942,8 @@ class XRPlayerManager { const l = this.playingCameraTweenGroup.cameraTweens.length; if (l > 1) { let name = null; - if (this.playingCameraTweenGroup.cameraTweens[l - 1].pos0.hasOwnProperty('name')) { - name = this.playingCameraTweenGroup.cameraTweens[l - 1].pos0.name; + if (this.playingCameraTweenGroup.cameraTweens[l - 1].pos1.hasOwnProperty('name')) { + name = this.playingCameraTweenGroup.cameraTweens[l - 1].pos1.name; } names.push(name); } From 5ec1316c47e83de7b9569e7d3688865b48e3361a Mon Sep 17 00:00:00 2001 From: bigint405 Date: Mon, 1 Feb 2021 15:46:05 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=B0=86=E7=83=AD=E7=82=B9=E4=B8=ADevent?= =?UTF-8?q?=E6=94=BE=E5=88=B0hotspotmap=E4=B8=AD=EF=BC=8C=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E7=83=AD=E7=82=B9=E5=AF=BC=E5=87=BA=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/app.js | 31 +++---- public/mock/view1.json | 152 +++++++++++++++---------------- src/display/SpriteShapeHelper.js | 68 +++++++++----- src/manager/XRPlayerManager.js | 8 +- 4 files changed, 141 insertions(+), 118 deletions(-) diff --git a/example/src/app.js b/example/src/app.js index b832793..647630d 100644 --- a/example/src/app.js +++ b/example/src/app.js @@ -93,24 +93,28 @@ class App extends React.Component { onAddHotSpot = () => { this.xrManager.addHotSpot({ - key: `infocard`, + key: 'infocard_test', value: { - lat: - 90, lon: -10, + lat: 90, lon: 0, res_url: 'https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png' } }, { - key: `infocard`, - value: { - id: 'infocard', - type: 'infocard', - iframeUrl: "https://gs.ctrip.com/html5/you/place/14.html" + type: "event_pop_effect_panel", + props: { + name: "infocard", + props: { + data: { + type: "infocard", + iframeUrl: "https://gs.ctrip.com/html5/you/place/14.html" + } + } } - }) + }); alert(`添加了一个热点标签`) } onRemoveHotSpot = () => { - this.xrManager.removeHotSpot('infocard') + this.xrManager.removeHotSpot('infocard_test') alert(`移除了一个热点标签`); } @@ -338,14 +342,7 @@ class App extends React.Component { } debugFunc = () => { - EventBus.trigger(Events.EVENT_POP_EFFECT_PANEL, { - name: "image", - props: {data:{ - type: "image", - imageUrl: "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", - jumpUrl: "http://www.youmuvideo.com" - }} - }); + console.log(this.xrManager.exportConfig()); } diff --git a/public/mock/view1.json b/public/mock/view1.json index 4ba558c..14e9b5f 100644 --- a/public/mock/view1.json +++ b/public/mock/view1.json @@ -36,17 +36,17 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/zhong_shan_she_qu.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "image", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "type": "image", - "imageUrl": "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", - "jumpUrl": "http://www.youmuvideo.com" + "name": "image", + "props": { + "data": { + "type": "image", + "imageUrl": "https://pic-cloud-bupt.oss-cn-beijing.aliyuncs.com/5c882ee6443a5.jpg", + "jumpUrl": "http://www.youmuvideo.com" + } } } } @@ -63,16 +63,16 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/zhong_shan_ji_nian_tang.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "video", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "type": "video", - "videoUrl": "https://video-cloud-bupt.oss-cn-beijing.aliyuncs.com/hangzhou.mp4" + "name": "video", + "props": { + "data": { + "type": "video", + "videoUrl": "https://video-cloud-bupt.oss-cn-beijing.aliyuncs.com/hangzhou.mp4" + } } } } @@ -90,16 +90,16 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/lin_ze_xu_chu_sheng_di.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "infocard", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "type": "infocard", - "iframeUrl": "https://gs.ctrip.com/html5/you/place/14.html" + "name": "infocard", + "props": { + "data": { + "type": "infocard", + "iframeUrl": "https://gs.ctrip.com/html5/you/place/14.html" + } } } } @@ -116,23 +116,23 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/tang_dai_ma_qiu_chang_yi_zhi.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "alpha_video", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } } } } @@ -149,23 +149,23 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "alpha_video", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } } } } @@ -183,23 +183,23 @@ "res_url": "https://live360.oss-cn-beijing.aliyuncs.com/xr/icons/hotspot_video.png", "img_url": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ou_ye_chi_yi_zhi.jpg", "img_height": 100, - "img_width": 150 - }, - "event": { - "type": "event_pop_effect_panel", - "props": { - "name": "alpha_video", + "img_width": 150, + "event": { + "type": "event_pop_effect_panel", "props": { - "data": { - "id": "video", - "type": "alpha_video", - "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", - "width": "60vw", - "height": "60vw", - "enableClose": true, - "margin": "auto auto", - "videoMuted": false, - "enableMask": true + "name": "alpha_video", + "props": { + "data": { + "id": "video", + "type": "alpha_video", + "videoUrl": "https://youmucloud.oss-cn-beijing.aliyuncs.com/xr/fuzhou/ren_shou_tang.mp4", + "width": "60vw", + "height": "60vw", + "enableClose": true, + "margin": "auto auto", + "videoMuted": false, + "enableMask": true + } } } } diff --git a/src/display/SpriteShapeHelper.js b/src/display/SpriteShapeHelper.js index dd558cc..28d412b 100644 --- a/src/display/SpriteShapeHelper.js +++ b/src/display/SpriteShapeHelper.js @@ -30,16 +30,21 @@ class SpriteShapeHelper { initHandler = () => { this.objectClickHandler = (intersects) => { const key = intersects[0].object.name; - if (this.eventMap && this.eventMap.has(key)) { - const data = this.eventMap.get(key); - EventBus.trigger(data.type, data.props); + if (this.hotSpotMap && this.hotSpotMap.has(key)) { + let hotSpot = this.hotSpotMap.get(key); + let event = hotSpot.event; + if (event) { + EventBus.trigger(event.type, event.props); + } } }; this.tagClickHandler = (key) => { - if (this.eventMap && this.eventMap.has(key)) { - const data = this.eventMap.get(key); - console.log(data) - EventBus.trigger(data.type, data.props); + if (this.hotSpotMap && this.hotSpotMap.has(key)) { + let hotSpot = this.hotSpotMap.get(key); + let event = hotSpot.event; + if (event) { + EventBus.trigger(event.type, event.props); + } } } } @@ -85,34 +90,38 @@ class SpriteShapeHelper { setHotSpotList = (hot_spot_list) => { this.resetHotSpotGroup(); this.hotSpotMap = new Map(); - this.eventMap = new Map(); + // this.eventMap = new Map(); hot_spot_list.forEach((spot) => { this.hotSpotMap.set(spot.key, spot.props); - this.eventMap.set(spot.key, spot.event); }); this.hotSpotMap.forEach((value, key) => { this.createPoint(key, value) }); } - setEventList = (eventList) => { - this.eventMap = new Map(eventList); - console.log('event_map') - console.log(this.eventMap) - } + // setEventList = (eventList) => { + // this.eventMap = new Map(eventList); + // console.log('event_map') + // console.log(this.eventMap) + // } - addHotSpot = (hot_spot) => { + addHotSpot = (hot_spot, event) => { if (!this.pointGroup) { this.resetHotSpotGroup(); } - this.createPoint(hot_spot.key, hot_spot.value) + this.hotSpotMap || (this.hotSpotMap = new Map()); + if (!!!hot_spot.value) return false; + hot_spot.value.event = event; + this.hotSpotMap.set(hot_spot.key, hot_spot.value); + this.createPoint(hot_spot.key, hot_spot.value); + return true; } - addEvent = (event) => { - if (event && !this.eventMap.has(event.key)) { - this.eventMap.set(event.key, event.value); - } - } + // addEvent = (event) => { + // if (event && !this.eventMap.has(event.key)) { + // this.eventMap.set(event.key, event.value); + // } + // } /** * 清空场景中的所有热点标签 @@ -127,6 +136,7 @@ class SpriteShapeHelper { this.container.removeChild(div); } }); + this.hotSpotMap = new Map(); } removeHotSpot = (hot_spot_key) => { @@ -134,6 +144,22 @@ class SpriteShapeHelper { if (mesh) { this.pointGroup.remove(mesh); } + this.hotSpotMap.delete(hot_spot_key); + this.hotSpotMap && (this.hotSpotMap.delete(hot_spot_key)); + } + + /** + * @function + * @name SpriteShapeHelper#exportConfig + * @description 导出热点标签配置信息 + */ + exportConfig = () => { + if (!!!this.hotSpotMap) return []; + let config = []; + this.hotSpotMap.forEach((value, key) => { + config.push({key: key, props: value}); + }); + return config; } convertSph2Rect = (lat, lon) => { diff --git a/src/manager/XRPlayerManager.js b/src/manager/XRPlayerManager.js index a54a7fb..adefee4 100644 --- a/src/manager/XRPlayerManager.js +++ b/src/manager/XRPlayerManager.js @@ -257,8 +257,9 @@ class XRPlayerManager { // TODO 需要从状态中读取,即需要解决一致性问题 config.volume = this.senceConfig.volume; config.muted = this.senceConfig.muted; - config.hot_spot_list = this.senceConfig.hot_spot_list; - config.event_list = this.senceConfig.event_list; + + config.hot_spot_list = this.spriteShapeHelper.exportConfig(); + config.model_list = this.senceConfig.model_list; config.particle_effect = this.senceConfig.particle_effect; config.auto_guide_list = this.senceConfig.auto_guide_list; @@ -362,8 +363,7 @@ class XRPlayerManager { } addHotSpot = (hot_spot, event) => { - this.spriteShapeHelper.addHotSpot(hot_spot); - this.spriteShapeHelper.addEvent(event); + return this.spriteShapeHelper.addHotSpot(hot_spot, event); } removeHotSpot = (hot_spot_key) => {