xzw 6 月之前
父節點
當前提交
f5314d17a0
共有 7 個文件被更改,包括 1863 次插入589 次删除
  1. 211 63
      js/Hot.js
  2. 40 33
      js/TransformControls.js
  3. 607 122
      js/edit.js
  4. 5 0
      js/loadCAD.js
  5. 284 128
      js/main_2020_edit.js
  6. 497 143
      js/main_2020_show.js
  7. 219 100
      js/manage.js

+ 211 - 63
js/Hot.js

@@ -4,18 +4,20 @@ g_currentHot = null
 
 
 
-
-
+let texLoader
  
 
 const playVideoWhenFlyOut = false
 //同时可播放的最大个数:
-const playVideoMax = window.isEdit ? 3  :   browser.isMobile() ? 1 : 3;   
+const videoHasSound = false
+const playVideoMax = videoHasSound ? 1 :( window.isEdit ? 3 : browser.isMobile() ? 1 : 3);    
 const playAniMax = window.isEdit ? 6 :   browser.isMobile() ? 3 : 5;
 
 const playSyncGroup = [//需要播放同步的视频。  每次都单独定制
    // ['okh1UR466371',  'LGmLHP2615503' ,  'VNyBI6614896'] //中,左,右   场景SHANGJJ
 ]
+ 
+
 
 window.initHot = function(model){
       
@@ -133,14 +135,21 @@ window.initHot = function(model){
         }
     }
 
+ 
+    const ctlBtns = {
+        play : Texture.load('images/soundPlay.png') ,
+        pause: Texture.load('images/soundPause.png') 
+    } 
+     
+    const ctlBtn = new THREE.Mesh(_planeGeometry,new THREE.MeshBasicMaterial({map:ctlBtns.pause, depthTest:false,  transparent:true}))
+    ctlBtn.name = 'ctlBtn'
+    ctlBtn.renderOrder = 5
+    
+    
+    
+    
 
-
-
-
-
-
-
-
+window.ctlBtn = ctlBtn
     
     class Hot extends THREE.Object3D{
         constructor(info, source){    
@@ -164,8 +173,7 @@ window.initHot = function(model){
 
 
         build(info) { 
-            hotGroup.add(this)
-            this.setTitleElem()          
+            hotGroup.add(this) 
             this.setFromInfo(info)
         }
         
@@ -229,7 +237,13 @@ window.initHot = function(model){
                 }    
             }
             
+            //设置visibles floor------------------
+            if(window.isEdit)this.setVisiblePanos(); 
+            else this.getFloor() //可能需要分批计算 
             
+            this.setTitleElem()  
+            this.update(player) //when edit done sprite update quaternion
+            //------------------------------------
             
             /*  if(this.info.modelBound){
                 this.mesh.updateMatrixWorld()
@@ -374,8 +388,10 @@ window.initHot = function(model){
                 
                 
                 
-                video.volume = 0
-                video.muted = true
+                if(!videoHasSound){
+                    video.volume = 0 
+                    video.muted = true 
+                }
                 video.currentTime = 0
                 
                 
@@ -646,9 +662,77 @@ window.initHot = function(model){
         }*/
         
         setVisiblePanos(visibleData){
-            if(visibleData)this.info.visiblePanos = visibleData  
-            else if(!this.info.visiblePanos) this.getVisiblePanos() 
+            if(visibleData){
+                this.info.visiblePanos = visibleData  
+            }else if(!this.info.visiblePanos){
+                this.getVisiblePanos() 
+            }
+            this.getFloor()
         } 
+    
+        getFloor(){//用于飞出后分层展示。最好只属于一个楼层,且是贴得最近的
+            //先直接向下探测
+            //不准的话再向四周选三个方向,以及visiblePanos,来加成求分
+            if(player.model.floors.list.length <= 1)return
+            if(this.floorByRay){
+                return this.floor = this.floorByRay  //重复getFloor的话,因模型不会变,用ray得到的floor不会变
+            }
+            
+            let result
+            if(this.floorByRay !== false){ 
+                let map = new Map
+                
+                
+                let downVec = new THREE.Vector3(0,-1,0)
+                 
+                let pos = this.info.transformAtPanos.outSide?.pos || this.position
+                let centerPos
+                if(!this.plane){
+                    let bound = new THREE.Box3().copy(this.info.modelBound.bound)
+                    let center = bound.center()
+                    let qua = this.info.transformAtPanos.outSide?.qua || this.quaternion
+                    let scale = this.info.transformAtPanos.outSide?.scale || this.scale
+
+                    var matrixWorld = new THREE.Matrix4().compose(pos, qua, scale)
+                    matrixWorld.multiplyMatrices(matrixWorld, this.mesh.matrix) 
+                    centerPos = center.applyMatrix4(matrixWorld);  
+                }else{
+                    centerPos = pos
+                } 
+            
+                let request = [(floor)=>{
+                    player.raycaster.set(centerPos,  downVec) 
+                    let n = player.raycaster.intersectObjects(floor.collider.children , true ); 
+                    if(n && n[0]){
+                        map.set(floor, n[0].distance)
+                        return true
+                    } 
+                }]
+                let rank = [(floor)=>{
+                    return - map.get(floor)
+                }]
+                
+                result = common.sortByScore(player.model.floors.list, request, rank)
+                
+            }
+            if(result){
+                this.floor = this.floorByRay = result[0].item
+            }else{ 
+                this.floorByRay = false //标记 使用ray无法找到
+                console.warn('热点通过raycaster没有找到楼层', this)
+                
+                if(this.info.visiblePanos){ 
+                    let floorIndex = this.info.visiblePanos.map(e=>player.model.panos.index[e].floorIndex).sort()[Math.floor(this.info.visiblePanos.length/2)]//中位数
+                    this.floor = player.model.floors.index[floorIndex]
+                    console.log('热点根据visiblePanos找到楼层', this, this.floor.name)
+                }else{
+                    this.floor = null
+                }
+            }
+                    
+             
+            
+        }
         
         getVisiblePanos(){//在不同点还不一样  
             var depth = this.hasBox ? this.scale.z  : 0;
@@ -682,14 +766,14 @@ window.initHot = function(model){
             }
 
     
-            var getPos = (position)=>{//每个overlay位置对应5个坐标,plane中心和四个角的位置
+            var getPos = (position, quaternion=this.info.quaternion, scale=this.info.scale)=>{//每个overlay位置对应5个坐标,plane中心和四个角的位置
                 if(this.plane){  
                     return cornerPoint.map(e=>{
                         return e.clone().applyQuaternion(this.info.quaternion).add(position)
                     })
                     
                 }else{ 
-                    var matrixWorld = new THREE.Matrix4().compose(position, this.quaternion, this.scale)
+                    var matrixWorld = new THREE.Matrix4().compose(position, quaternion, scale)
                     matrixWorld.multiplyMatrices(matrixWorld, this.mesh.matrix) 
                      
                     return cornerPoint.map(e=>{
@@ -706,7 +790,8 @@ window.initHot = function(model){
         
             for(let panoId in this.info.transformAtPanos){
                 if(panoId == 'outSide')continue;
-                posAtPanos[panoId] = getPos(this.info.transformAtPanos[panoId].pos ) 
+                let {pos,qua,scale} = this.info.transformAtPanos[panoId]
+                posAtPanos[panoId] = getPos(pos,qua,scale) 
             }   
             
                     
@@ -715,9 +800,15 @@ window.initHot = function(model){
             let maxCount = browser.isMobile() ? 2000 : 5000
             
             let possiblePanos = model.panos.list
-            if(this.plane){//目前都是单面,所以只要可以看到的一面的热点
-                let dir1 = new THREE.Vector3(0,0,-1).applyQuaternion(this.quaternion).negate()
+            if(this.plane && !this.info.isSprite){//目前都是单面,所以只要可以看到的一面的热点 
+                let defaultDir = new THREE.Vector3(0,0,-1).applyQuaternion(this.info.quaternion).negate()
                 possiblePanos = possiblePanos.filter(pano=>{ 
+                    let dir1
+                    if(this.info.transformAtPanos[pano.id]?.qua){
+                        dir1 = new THREE.Vector3(0,0,-1).applyQuaternion(this.info.transformAtPanos[pano.id].qua).negate()  
+                    }else{
+                        dir1 = defaultDir
+                    }  
                     let dir2 = new THREE.Vector3().subVectors(pano.position, this.position).normalize();
                     return dir1.dot(dir2)>0
                 })
@@ -727,8 +818,7 @@ window.initHot = function(model){
             if(window.isEdit ||  c < maxCount){  //编辑页面保险起见还是全部算完后才可浏览,就能保证保存全部的visiblePano
                 this.info.visiblePanos = common.getVisiblePano(customPositions, possiblePanos , {
                     model: model.colliders , posAtPanos  
-                })  
-                
+                })   
             }else{
                 let start = 0
                 let interval = setInterval(()=>{
@@ -745,6 +835,7 @@ window.initHot = function(model){
                     
                     if(end>=possiblePanos.length){
                         //console.log(window.hotsi ?(++window.hotsi): (window.hotsi = 1))
+                        this.getFloor() //re get
                         clearInterval(interval)
                     }
                 }, Hot.visiEveryDurSlice )// visiEveryDurSlice 等在main中定义
@@ -752,9 +843,10 @@ window.initHot = function(model){
             
         }
         
+        
             
         updateVisible(panos, visibility, type) { 
-            if(window.isEdit && editTool.hotpoint.editSpot == this){
+            if(window.isEdit && editTool.hotpoint.editSpot == this || player.mode != 'panorama' && visibility !== false){
                 return convertTool.updateVisible(this,'visi',true) 
             }
             
@@ -773,6 +865,10 @@ window.initHot = function(model){
             } 
         }
         
+        getWorldCenter(){
+            return this.getBoundOri().center().applyMatrix4(this.mesh.matrixWorld)
+        }
+        
         getBoundOri(){
             let bound
             if(this.objObject){
@@ -928,13 +1024,21 @@ window.initHot = function(model){
                 let min = new THREE.Vector2(5,5)
                 let scaleRatio = 1/player.zoomLevel;
                 
+                
+                /* 
                 //根据media原始大小来调整阈值:  media的原始大小能代表期望显示的大小,如果显示大小的远小于期望大小,就不显示(此时能感受到贴图锯齿严重,清晰度被浪费)。比如如果gif是一个很小的按钮,即使diffLon很小也要显示。缺点:需要用户根据所需上传合适清晰度的图。
-           
                 let size = this.getMediaSize()
                 if(size.x>0){
                     scaleRatio *= Math.sqrt(size.x * size.y) / 1000
                 }
                 min.multiplyScalar(scaleRatio)
+                2025.2:不行,这样大的视频贴上去很容易返回false
+                */
+                
+                //gif如果是一个按钮,需要更小的lon  . 最好是能有滑块调节可视
+                if(this.animation){
+                    min.multiplyScalar(0.5)
+                }
                 
                 
                 if(cornerPointInfo.diffLon < min.x || cornerPointInfo.diffLat < min.y ){
@@ -984,13 +1088,13 @@ window.initHot = function(model){
             this.updateTitle()
         }
                     
-        updateScale(e, t) {//自适应调节大小 
+        updateScale(e, t) {//自适应调节大小   
             if(!DATA.autoAdjustHotScale || this.texType != 'shine' || !this.plane )return
-             
+           
             var scale = convertTool.getScaleForConstantSize($.extend({},autoSizeInfo,{ 
                 position: this.position.clone()  
             }))
-            this.plane.scale.set(scale,scale,scale)
+            this.plane.scale.set(scale,scale,scale)   //修改mesh,和自定义修改的scale不冲突
             
         }                
 
@@ -1012,38 +1116,45 @@ window.initHot = function(model){
             if(this.texType != "video" || !this.material_.map)return
             var video = this.texMedia
             this.shouldPlay = state
-            
-            
-            
+             
             if(!state || state == 'stop'){
                 if(!video.paused){
                     video.pause()
-                    //console.log({str: "paused " + this.sid, level:1})
+                    if(!video.muted){
+                        SoundManager.pause('hot', true)//自动播放被中断的音频 (bgm 
+                    }
+                    console.log({str: "paused " + this.sid, level:1})
                 }
                 /* video.lastCurTime = state == 'stop' ? 0 : video.currentTime //记录
-                video.src = video.src_ = '' */
-                
+                video.src = video.src_ = '' */ 
                 if(state == 'stop'){
                     video.currentTime = 0; 
                 }  
+                if(this.sid == 'LezWqUp088015'){
+                    ctlBtn.material.map = ctlBtns.play
+                }
             }else if(state){
                 if(/* !isVideoPlayed(video) */  video.paused  ){
-                    //console.log({str: 'videoControl play ' +", "+ this.sid,  level:1})
+                     console.log({str: 'videoControl play ' +", "+ this.sid,  level:1})
                     this.loadVideo(video)
                     video.play()
+                    if(!video.muted){
+                        SoundManager.play('hot') //暂停bgm等
+                    }
                     //video.currentTime = video.lastCurTime || 0
                     this.changeOpaWhenPlay(video)
                     
+                    if(this.sid == 'LezWqUp088015'){
+                        ctlBtn.material.map = ctlBtns.pause
+                    }
+                    
                     //处理同步播放
                     let group = playSyncGroup.find(e=>e.includes(this.sid))
                     if(group){
                         let others = group.filter(e=>e != this.sid).map(e=>player.model.hots[e].texMedia)
                         //console.log('controlVideo play', this.id, 'other currentTime', others.map(e=>e.currentTime))
                         video.currentTime = others[0].currentTime
-                    }
-                    
-                    
-                    
+                    }  
                     //if(isVideoPlayed(video))console.log({str:"played " + this.sid + video.duration ,level:1})              
                 }                    
                   
@@ -1123,13 +1234,25 @@ window.initHot = function(model){
             var v = this.info.titleShowType != 'unvisible' && (this.info.titleShowType == 'always' || this.hovered)
             this.titleElem.setVisible(v, 'hoveredVisi', 1)
             //this.updateTitle()  
+            
+            if(this.sid == 'LezWqUp088015'){
+                if(state){
+                    this.add(ctlBtn)    //显示按钮
+                    let scale = 0.8
+                    ctlBtn.scale.set(scale/this.scale.x,scale/this.scale.y,scale/this.scale.z)
+                    ctlBtn.rotation.set(0,Math.PI/2,Math.PI/2)
+                    ctlBtn.position.x = -0.15
+                }else{
+                    this.remove(ctlBtn)
+                } 
+            }
         }
         
        
-        closestPanoTowardTag(e, t) {
+        closestPanoTowardTag(e ) {
             var i = []
               , n = []
-              , r = this.mesh.getWorldPosition();
+              , r = this.getWorldCenter()//  this.mesh.getWorldPosition();
             if (e === "panorama") {
                 /* var o = t.position.clone().sub(r).normalize();
                 n.push(function(t, i) {//scoreFunctions.direction 最好这个漫游点在currentPano到热点之间的路径上。但是这样的话可能就看不到热点正面,所以删掉
@@ -1198,11 +1321,8 @@ window.initHot = function(model){
                         return result; 
                     } 
                 ) */    
-                
-                
-                
-                
-            var s = t.model.panos.sortByScore(i, n);
+                 
+            var s = player.model.panos.sortByScore(i, n);
             //console.log(s) 
             return s && 0 < s.length && s[0].item
         }
@@ -1214,14 +1334,21 @@ window.initHot = function(model){
         examine(options={}) {
             var openHot = this.info.link && this.info.actionType.openHot && !options.dontOpen
             var fastTran = !options.dontFastTran && ( this.info.actionType.fastTran || settings.hotFastTran || options.fastTran)
-            if(fastTran){//瞬间过渡 1到固定方位 2到和普通过渡一样的位置,也就是最适合的位置
+            if(fastTran){//瞬间过渡 1到固定方位 2到和普通过渡一样的位置,也就是最适合的位置 
                 let info = this.info.cameraData  
                 if(info){
                     player.blackToPano({
                         pano: player.model.panos.index[info.pano.uuid],
                         quaternion: new THREE.Quaternion().fromArray(info.camera.quaternion)
                     }) 
-                }                
+                }else{
+                    let pano = this.closestPanoTowardTag(player.mode ) || player.currentPano,
+                        pos = this.getWorldCenter(),
+                        m = (new THREE.Matrix4).lookAt(pano.position, pos, new THREE.Vector3(0,1,0)),
+                        quaternion = new THREE.Quaternion().setFromRotationMatrix(m)  
+
+                    player.blackToPano({pano,quaternion}) 
+                }              
             }
             
             
@@ -1335,8 +1462,8 @@ window.initHot = function(model){
                 return;
             }
         
-            var c = this.closestPanoTowardTag(player.mode, player.currentPano) || player.currentPano
-              , h = this.mesh.getWorldPosition();
+            var c = this.closestPanoTowardTag(player.mode ) || player.currentPano
+              , h = this.getWorldCenter()//this.mesh.getWorldPosition();
             player.flyingToTag = !0;
             
             
@@ -1456,20 +1583,21 @@ window.initHot = function(model){
                     this.mesh.boxHelper = new THREE.Box3Helper( bound,  new THREE.Color( "#00ffff"));
                     this.mesh.add(this.mesh.boxHelper) 
                     this.mesh.boxHelper.material.depthTest = false;
-                    this.mesh.boxHelper.material.transparent = true
-                    this.mesh.boxHelper.visible = false
+                    this.mesh.boxHelper.material.transparent = true  
                 }
+                convertTool.updateVisible(this.mesh.boxHelper,'defaultHide', false)//默认隐藏
             }
         } 
         
-        changeBoxHelperDisplay(show){
+        changeBoxHelperDisplay(show,reason='hover'){
             if(show){//暂时先把模型强制显示,以展示 boxHelper 
                 convertTool.updateVisible(this, 'showBoxHelper', true, 2, 'add')
-                
-                this.mesh.boxHelper.visible = true
+                convertTool.updateVisible(this.mesh.boxHelper, 'highlight_'+reason, true, 2, 'add')
+
             }else{
                 convertTool.updateVisible(this, 'showBoxHelper', false, 2, 'cancel')
-                this.mesh.boxHelper.visible = false
+                convertTool.updateVisible(this.mesh.boxHelper, 'highlight_'+reason, false, 2, 'cancel')
+     
             }
             
         } 
@@ -1491,9 +1619,8 @@ window.initHot = function(model){
                     return; //为什么之前1191需要在这加callback() 才能呢。现在又没事了
                 }
                 //console.log(' beginDownload : ' + this.sid)
-                
                  
-                /* this.material_.map =  */Texture.load(this.info.texSrc, (tex)=>{ 
+                Texture.load(this.info.texSrc, (tex)=>{  
                     callback && callback()
                     if(!tex.image ){
                         return  //只是单纯用了相同src的tex,但image仍未加载完
@@ -1518,6 +1645,7 @@ window.initHot = function(model){
                                 if(window.isEdit){
                                     if(animateTexSrcs[e.info.texSrc]){
                                         e.material_.map = tex.clone(); //编辑动画直接不用一个texture, 故而animation也不同
+                                        e.material_.map.repeat.set(1,1), e.material_.map.offset.set(0,0)
                                         e.material_.map.needsUpdate = true
                                         
                                     }else{
@@ -1534,6 +1662,8 @@ window.initHot = function(model){
                                         }
                                         if(!finded){
                                             let tex_ = tex.clone();
+                                            tex_.repeat.set(1,1), tex_.offset.set(0,0)
+                                            
                                             tex_.needsUpdate = true //clone后不写这句会黑块
                                             animateTexSrcs[e.info.texSrc].set(e.info.animateInfo, tex_)  
                                             e.material_.map = tex_ 
@@ -1579,11 +1709,10 @@ window.initHot = function(model){
 
             }else if(type == 'model'){
                 if(this.modelHasRequestLoad || !this.info.objSrc)return;
-                
-                 //需要处理重复? 
+                 
                 objLoader.load(this.info.objSrc, (object)=>{
                     this.remove(this.mesh)
-                    this.addModel(object)
+                    this.addModel(object) //复制的也包含boxHelper(也是复制的)
                     
                     callback && callback()
                     if(++modelLoaded == originModelCount){//data2.js中的所有photo加载完毕
@@ -1693,11 +1822,11 @@ window.initHot = function(model){
             return true
         }];
         var rank = [(item)=>{
-            var dis = item.hot.mesh.getWorldPosition().distanceTo(player.position);
+            var dis = item.hot.getWorldCenter().distanceTo(player.position);
             return -dis
         }
         , (item)=>{
-            var tagDir = item.hot.mesh.getWorldPosition().sub(player.position)
+            var tagDir = item.hot.getWorldCenter().sub(player.position)   //mesh.getWorldPosition()
             var angle = tagDir.angleTo(cameraDir)
             return -angle * 20
         }]
@@ -1753,6 +1882,19 @@ window.initHot = function(model){
         
         
         player.emit('gotHotAndStartload')
+        
+        
+        if(player.model.floors.list.length>1){
+            player.model.on("floor.changed",(currentFloor, mode, oldFloor)=>{
+                //this.update(currentFloor)  //注: currentFloor 这时候还没成为 model.currentFloor
+                let showAll = mode == 'panorama' || player.model.allFloorsVisible 
+                hotGroup.children.forEach(e=>{
+                    convertTool.updateVisible(e,'floor',showAll || e.floor == currentFloor) 
+                })
+                //console.log(currentFloor, mode, oldFloor) 
+            })
+        }
+        
     }
     
     window.Hot = Hot   
@@ -1970,6 +2112,8 @@ function isVideoPlayed(video){
     return !video.paused && !isNaN(video.duration) //注意,有的手机首次play时会立即paused为false,但其实没加载好, duration为NAN      
 }
 
+
+
 /* 
 
 
@@ -1989,6 +2133,8 @@ function isVideoPlayed(video){
     所以尽量降到2000以下 同时播放个数最好不超过2个 可能需要将src归零  并延迟加载、不自动播放
     
     
+    videoWidth和帧宽度竟然不一定一样,帧宽度3840,帧高度2160,但是竖屏视频,videoWidth为3840,videoHeight为6833
+    video宽高达到 videoWidth 3840, videoHeight 6833时  在安卓无法播放。可能是高于4096的原因。
     
     
     有遇到某张图在ios里显示不出,但在ps重新输出后就可以。这张图的dpi高达500,不知道是否与此有关。
@@ -2000,4 +2146,6 @@ function isVideoPlayed(video){
     显示故障的机型:
     视频黑屏(4dkk视频漫游点也无法播放):小米10(自带浏览器)、红米K40(微信浏览器)、
     
+    
+    贴图safari黑色的,很可能是使用CMYK模式的原因,dpi>96了 
 */

+ 40 - 33
js/TransformControls.js

@@ -41,7 +41,8 @@ var TransformControls = function ( camera, domElement, options ) {
 
 	var _gizmo = new TransformControlsGizmo(options);
 	this.add( _gizmo );
-
+    this._gizmo = _gizmo
+    
 	var _plane = new TransformControlsPlane(options);
 	this.add( _plane );
 
@@ -796,7 +797,7 @@ var TransformControlsGizmo = function (options) {
 	Object3D.call( this );
 
 	this.type = 'TransformControlsGizmo';
-
+    this.hideAxis = {} //add
 	// shared materials
 
 	var gizmoMaterial = new MeshBasicMaterial( {
@@ -1266,10 +1267,15 @@ var TransformControlsGizmo = function (options) {
 		for ( var i = 0; i < handles.length; i ++ ) {
 
 			var handle = handles[ i ];
-
+            //add
+            if(this.hideAxis[this.mode] && this.hideAxis[this.mode].some(e=>handle.name.includes(e.toUpperCase()))){
+                convertTool.updateVisible(handle, 'hidden', false)
+                continue 
+            } 
 			// hide aligned to camera
-
-			handle.visible = true;
+            let visible = true  //handle.visible = true;
+            
+             
 			handle.rotation.set( 0, 0, 0 );
 			handle.position.copy( this.worldPosition );
  
@@ -1279,12 +1285,12 @@ var TransformControlsGizmo = function (options) {
 
 			if ( handle.tag === 'helper' ) {
 
-				handle.visible = false;
+				visible = false;
 
 				if ( handle.name === 'AXIS' ) {
 
 					handle.position.copy( this.worldPositionStart );
-					handle.visible = !! this.axis;
+					visible = !! this.axis;
 
 					if ( this.axis === 'X' ) {
 
@@ -1293,7 +1299,7 @@ var TransformControlsGizmo = function (options) {
 
 						if ( Math.abs( alignVector.copy( unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
 
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1306,7 +1312,7 @@ var TransformControlsGizmo = function (options) {
 
 						if ( Math.abs( alignVector.copy( unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
 
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1319,7 +1325,7 @@ var TransformControlsGizmo = function (options) {
 
 						if ( Math.abs( alignVector.copy( unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > 0.9 ) {
 
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1331,13 +1337,13 @@ var TransformControlsGizmo = function (options) {
 						alignVector.copy( this.rotationAxis );
 						handle.quaternion.setFromRotationMatrix( lookAtMatrix.lookAt( zeroVector, alignVector, unitY ) );
 						handle.quaternion.multiply( tempQuaternion );
-						handle.visible = this.dragging;
+						visible = this.dragging;
 
 					}
 
 					if ( this.axis === 'E' ) {
 
-						handle.visible = false;
+						visible = false;
 
 					}
 
@@ -1345,12 +1351,12 @@ var TransformControlsGizmo = function (options) {
 				} else if ( handle.name === 'START' ) {
 
 					handle.position.copy( this.worldPositionStart );
-					handle.visible = this.dragging;
+					visible = this.dragging;
 
 				} else if ( handle.name === 'END' ) {
 
 					handle.position.copy( this.worldPosition );
-					handle.visible = this.dragging;
+					visible = this.dragging;
 
 				} else if ( handle.name === 'DELTA' ) {
 
@@ -1359,7 +1365,7 @@ var TransformControlsGizmo = function (options) {
 					tempVector.set( 1e-10, 1e-10, 1e-10 ).add( this.worldPositionStart ).sub( this.worldPosition ).multiplyScalar( - 1 );
 					tempVector.applyQuaternion( this.worldQuaternionStart.clone().inverse() );
 					handle.scale.copy( tempVector );
-					handle.visible = this.dragging;
+					visible = this.dragging;
 
 				} else {
 
@@ -1377,13 +1383,14 @@ var TransformControlsGizmo = function (options) {
 
 					if ( this.axis ) {
 
-						handle.visible = this.axis.search( handle.name ) !== - 1;
+						visible = this.axis.search( handle.name ) !== - 1;
 
 					}
 
 				}
 
 				// If updating helper, skip rest of the loop
+                convertTool.updateVisible(handle, 'hidden', !!visible)
 				continue;
 
 			}
@@ -1408,7 +1415,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1418,7 +1425,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1428,7 +1435,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) > AXIS_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1438,7 +1445,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitZ ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1448,7 +1455,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitX ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+							visible = false;
 
 						}
 
@@ -1458,7 +1465,7 @@ var TransformControlsGizmo = function (options) {
 						if ( Math.abs( alignVector.copy( unitY ).applyQuaternion( quaternion ).dot( this.eye ) ) < PLANE_HIDE_TRESHOLD ) {
 
 							handle.scale.set( 1e-10, 1e-10, 1e-10 );
-							handle.visible = false;
+                            visible = false;
 
 						}
 
@@ -1472,7 +1479,7 @@ var TransformControlsGizmo = function (options) {
 
 						/* if ( handle.tag === 'fwd' ) {
 
-							handle.visible = false;
+							visible = false;
 
 						} else {
 
@@ -1482,7 +1489,7 @@ var TransformControlsGizmo = function (options) {
 
 					} else if ( handle.tag === 'bwd' ) {
 
-						handle.visible = false;*/
+						visible = false;*/
 						handle.scale.x *= - 1;
 					} 
 					
@@ -1494,7 +1501,7 @@ var TransformControlsGizmo = function (options) {
 
 						/* if ( handle.tag === 'fwd' ) {
 
-							handle.visible = false;
+							visible = false;
 
 						} else {
 
@@ -1504,7 +1511,7 @@ var TransformControlsGizmo = function (options) {
 						
 					} else if ( handle.tag === 'bwd' ) {
 
-						handle.visible = false;
+						visible = false;
 						*/
 						handle.scale.y *= - 1;
 					} 
@@ -1517,7 +1524,7 @@ var TransformControlsGizmo = function (options) {
 
 						/* if ( handle.tag === 'fwd' ) {
 
-							handle.visible = false;
+							visible = false;
 
 						} else {
 
@@ -1527,7 +1534,7 @@ var TransformControlsGizmo = function (options) {
 
 					} else if ( handle.tag === 'bwd' ) {
 
-						handle.visible = false; */
+						visible = false; */
 						handle.scale.z *= - 1;
 					}
 
@@ -1573,11 +1580,11 @@ var TransformControlsGizmo = function (options) {
 			}
 
 			// Hide disabled axes
-			handle.visible = handle.visible && ( handle.name.indexOf( "X" ) === - 1 || this.showX );
-			handle.visible = handle.visible && ( handle.name.indexOf( "Y" ) === - 1 || this.showY );
-			handle.visible = handle.visible && ( handle.name.indexOf( "Z" ) === - 1 || this.showZ );
-			handle.visible = handle.visible && ( handle.name.indexOf( "E" ) === - 1 || ( this.showX && this.showY && this.showZ ) );
-
+			visible = visible && ( handle.name.indexOf( "X" ) === - 1 || this.showX );
+			visible = visible && ( handle.name.indexOf( "Y" ) === - 1 || this.showY );
+			visible = visible && ( handle.name.indexOf( "Z" ) === - 1 || this.showZ );
+			visible = visible && ( handle.name.indexOf( "E" ) === - 1 || ( this.showX && this.showY && this.showZ ) );
+            convertTool.updateVisible(handle, 'hidden', !!visible)
 			// highlight selected axis
 
 			handle.material._opacity = handle.material._opacity || handle.material.opacity;

文件差異過大導致無法顯示
+ 607 - 122
js/edit.js


+ 5 - 0
js/loadCAD.js

@@ -126,6 +126,11 @@ window.grendCAD = (function grendCAD() {
         window.cad.setSign(point, dire)
       }
       $layer.style.visibility = 'visible'
+      
+      
+      if(_settings.angleShift2d){
+        $layer.querySelector('svg').style.transform = 'rotate(-'+ _settings.angleShift2d +'deg)'//xzw 校准模型旋转
+      }
     })
 
   }

+ 284 - 128
js/main_2020_edit.js

@@ -3303,7 +3303,9 @@ function o(a, s, l) {
             
             if(_settings.floorPlanAngle){//指定了角度的话,就和browser.aspectRatio()无关,总使用纵向
                 var angle = parseFloat(_settings.floorPlanAngle)
-                    
+                /* if(_settings.angleShift2d){ //怎么算都会超出,仔细想了下是无法算准的
+                    angle += THREE.Math.degToRad(_settings.angleShift2d)
+                }  */   
                 
                 modelSize = modelSize.clone().applyEuler(new THREE.Euler(0, angle, 0))
                 
@@ -3314,7 +3316,8 @@ function o(a, s, l) {
                 ratio = ratio != void 0 ? ratio :  Math.max(screenSize *  defaultRatio / maxSize,  defaultRatio) ; 
                 
                 absoluteScale = n / 2 / l.orthoBase * ratio;  //根据模型所占最大视口尺寸调整缩放
-            }else{ 
+            }else{  
+            
                 var t = Math.max(modelSize.x, modelSize.z)
                   , i = Math.min(modelSize.x, modelSize.z)
                   , n = Math.max(t, i * this.camera.aspect)
@@ -3326,7 +3329,7 @@ function o(a, s, l) {
         
          
         
-        n.prototype.rotateToView = function(modelSize, direction) {
+        n.prototype.rotateToView = function(modelSize, direction, type) {
             let i = 0, n = p.aspectRatio() < 1  //是否模型尺寸显“细长” 
               
             if(_settings.floorPlanAngle ){//规定了cadImage旋转值的话 (0是无效的,将不设置)
@@ -3355,6 +3358,13 @@ function o(a, s, l) {
                 }
             }
               
+            if(_settings.angleShift2d){
+                i += THREE.Math.degToRad(_settings.angleShift2d)
+            }
+            
+            if(type == 'update'){//若不是update,只能是从其他模式刚转到floorplan
+                i += this.lon
+            }
 
             this.rotateLeft(i);
             this.update(0);
@@ -3362,11 +3372,16 @@ function o(a, s, l) {
             
         }
         ,
-        n.prototype.rotateToAngle = function(angle){//add  旋转到特定角度 
+        
+        n.prototype.updateRotate = function(angle){//add  在floorplan模式直接旋转 
+            this.rotateToView(player.model.size, player.getDirection(),'update'); 
+            
+        } 
+        /* n.prototype.rotateToAngle = function(angle){//add  旋转到特定角度 
             this.rotateLeft(angle + this.lon);
             this.update(0); 
             
-        }
+        } */
         ,
         
         
@@ -4755,6 +4770,61 @@ function o(a, s, l) {
                     }
                     .bind(this), this.goNext.bind(this))
             }
+            
+            
+            ,
+            
+            
+            
+            t.prototype.findNearestItem = function(endToStart=true){//找到离currentPano最近的导览
+                /* if(this.atDestinationPano(this.player.currentPano)){//在终点直接从头。但有的场景可能不希望如此,就想跳到所属的展区开始。
+                    return [0,0]   //2023.7.7发现在点击item后播放会从头开始
+                } */
+                //注:没有判断此刻是否在panorama模式,就使用currentPano
+            
+                var result = {item:[0,0], dis:Infinity};
+                
+                var compare = (location, item)=>{
+                    if(location.panoId != void 0 && location.panoId!= "outside"){
+                        var pano = this.model.panos.index[location.panoId];
+                        var dis = pano.position.distanceTo(this.player.currentPano.position)
+                        if(dis<result.dis){
+                            result.item = item, result.dis = dis
+                        }else if(dis == result.dis){//如果两个位置相同,优先播放在导览条上离激活的最近的那段导览 
+                            /* if(this.itemCompare(item,  this.currentItem, 'equal')){
+                                result.item = item, result.dis = dis
+                            } */ 
+                            if(this.currentItem && Math.abs(item[0]-this.currentItem[0]) < Math.abs(result.item[0]-this.currentItem[0])){
+                                result.item = item, result.dis = dis
+                            }  
+                        }
+                    } 
+                }
+                this.model.heroLocations.forEach((e,i)=>{
+                    if(e.heroLocations){
+                       /* e.heroLocations.forEach((a,j)=>{
+                           compare(a, [i,j])
+                       }) */
+                       var location = e.heroLocations.find(e=>e.panoId != void 0)
+                       location && compare(location, [i,0]) //跳到此区域开头
+                       
+                    }else{
+                       compare(e, [i,0])
+                    }  
+                    
+                })
+                
+                 
+                
+                if(endToStart && this.atEndOfTour(result.item)){ //如果是最后一个点,直接跳到开头,否则导览开始就在终点的话不会从头开始
+                    return [0,0]                                  //但注意最后是区域的话result.item是区域开头,除非站在最末最末尾的位置,上面的atDestinationPano直接返回
+                }
+                
+                return result.item
+                
+            }
+            
+            
             ,
             t.prototype.playTour = function() {
                 if (!this.bounceable())
@@ -4775,6 +4845,30 @@ function o(a, s, l) {
             }
             ,
             
+            t.prototype.playTourNearBy = function() {//就近导览
+                
+                if (!this.bounceable()){
+                    return this.tourIsPlaying ? void m.info("tour is already playing") : void (this.wouldInterrupt() || (this.player.emit("tour_auto", this.defaultWarpStyle),
+                    this.tourInProgress = !0,
+                    this.reachSource = "play",
+                    this.tourIsPlaying = !0,
+                    this.wasZoomEnabled = this.player.zoomEnabled,
+                    this.player.zoomEnabled = !1,
+                    this.resetSpecialTransition(),
+                    this.emit("update.controls"),
+                    this.emit(p.TourStart),
+                    this.player.enablePreRendering(),
+ 
+                    /* this.walkingSectionPaused ? (this.clearWalkingSectionPaused(),
+                    this.goToDestination()) : this.goNext())) */
+                    
+                    
+                    this.setDestinationItem(this.findNearestItem()) , this.goToDestination()) )
+               } 
+                
+                
+                
+            },
             t.prototype.stopTour = function(isAutoStop) {//停止导览        isAutoStop 希望仅在飞完结束自动停止时的stopTour不停止tourSound, 这样才能完整播放tourSound.  不过似乎会在倒数第二个片段点击按钮停止导览时也视作自动结束的(执行this.interrupt() )。
                 this.isInterrupted() || this.transitionStage === v.Moving && this.checkAndHandleWalkingtourInterruption(this.nextWarpStyle) || (this.tourIsPlaying && (this.player.zoomEnabled = this.wasZoomEnabled),
                 this.tourIsPlaying = !1,
@@ -8579,8 +8673,8 @@ function o(a, s, l) {
     84: [function(e, t, i) {
         "use strict";
         function n() {
-            //v.playTourNearBy(),
-            v.playTour(),
+             settings.playTourNearBy ? v.playTourNearBy() : v.playTour() 
+         
             y && clearTimeout(y),
             c(),
             E.removeClass("fadeIn")
@@ -14011,7 +14105,7 @@ function o(a, s, l) {
                 
                 t.hotIconScale = parseFloat(t.hotIconScale || 1) 
                 window.DATA = t
-                
+                settings.playTourNearBy = !DATA.tourFromStart
                 
                 t.model.summary = t.summary
                 t.model.name = t.name
@@ -14054,19 +14148,19 @@ function o(a, s, l) {
                     
                   
                      
-                    if (window.DATA.backgroundMusic) {
-                        if(window.isLocal){
-                            SoundManager.setSrc('bgm', manage.dealURL(window.DATA.backgroundMusic))
-                        }else{
-                            SoundManager.setSrc('bgm', window.DATA.backgroundMusic )
-                        } 
-                        $("#volume").show();
+                    if (window.DATA.backgroundMusic && window.isLocal) {
+                        window.DATA.backgroundMusic = manage.dealURL(window.DATA.backgroundMusic)
                     }else if (g_version === "one"){
-                        SoundManager.setSrc('bgm', manage.dealURL( g_Prefix+"/audio/"+"audio"+window.number + "/background.mp3"))
+                        window.DATA.backgroundMusic = manage.dealURL( g_Prefix+"/audio/"+"audio"+window.number + "/background.mp3")
+                    }
                     
                     
+                    if (window.DATA.backgroundMusic) {
+                        SoundManager.setSrc('bgm', window.DATA.backgroundMusic )
                         $("#volume").show();
                     }
+                     
+                     
                     
                     //隐藏公司logo
                     window.DATA.loadlogo && showLogo();
@@ -14249,7 +14343,12 @@ function o(a, s, l) {
                             }
                             
                             {//其他
-                                _settings.floorPlanAngle = DATA.floorPlanAngle || 0  
+                                _settings.floorPlanAngle = DATA.floorPlanAngle || 0 
+                                _settings.angleShift2d = DATA.angleShift2d || 0 
+                                if(DATA.insideLookLimit){
+                                    _settings.insideLookLimitDown = DATA.insideLookLimit[0] 
+                                    _settings.insideLookLimitUp = DATA.insideLookLimit[1] 
+                                }                                
                             }
                                   
                             
@@ -16840,70 +16939,57 @@ function o(a, s, l) {
                 }).done(function(e) { 
                     window.data2 = e;
                     this.roomLabels = []
-                    
-                    
-                    
-                    
-                    
-                    
-                    editTool.loadDone('data2', e)
-                    
-                     
+                       
                     if(!e){
                         console.error("data2 is null") 
                     }else{ 
                         g_data2 = hotMatcher(e)
                         this.hotsCount = 0;
                         //因为热点保存后在hots里的顺序会被修改,所以使用order来记录顺序,这里要重排序:
-                        //window.hotData = {}
+                          
+                        let create = ()=>{ 
+                            //alertInfo('开始计算',{dontAutoClose:true, hideCloseBtn:true, name:'getPanoVisibles'}); //暂时没找到很多热点要计算的场景
                         
-                        /* if(e.hots){
-                            var sids = Object.keys(e.hots).sort((a,b)=>{return e.hots[a].order - e.hots[b].order});
+                            if(e.hots){  
+                                var sids = Object.keys(e.hots).sort((a,b)=>{return e.hots[a].order - e.hots[b].order});
+                                sids.forEach((sid)=>{ 
+                                    e.hots[sid].sid = sid
+                                    if(e.hots[sid].texType == 'photo' && !e.hots[sid].texSrc)return console.error('有photo热点无texSrc',e.hots[sid])
+                                    
+                                    new Hot(e.hots[sid], e.hots[sid].version != 'multi' && "byHot" )
+                                })
+                            }
                             
-                            sids.forEach((sid)=>{
-                                this.hotsCount++,
-                                this.hots[sid] = new M(sid,e.hots[sid] ,this);
-                                //e.hots[sid].infoAttribute || (e.hots[sid].infoAttribute = {})
-                                //this.hots[sid].initStyleImg(e.hots[sid].infoAttribute);
-                                window.hotData[sid] = e.hots[sid];
-                            })  
-                        }*/
-                        
-                       
-                        
-                        if(e.hots){  
-                            var sids = Object.keys(e.hots).sort((a,b)=>{return e.hots[a].order - e.hots[b].order});
-                            sids.forEach((sid)=>{
-                                e.hots[sid].sid = sid
-                                new Hot(e.hots[sid], e.hots[sid].version != 'multi' && "byHot" )
-                            })
-                        }
-                        
-                        if(e.overlays){
-                            e.overlays.forEach((info)=>{ 
-                                new Hot(info, 'byOverlay')  
-                            })
+                            if(e.overlays){
+                                e.overlays.forEach((info)=>{ 
+                                    new Hot(info, 'byOverlay')  
+                                })
+                            }
+                            Hot.createHotList();
+                            
+                            
+                            if(DATA.roomLabels){
+                                DATA.roomLabels.forEach((data)=>{
+                                    this.roomLabels.push(new RoomLabel(data))
+                                })
+                            }
+                            
+                            //alertClose('getPanoVisibles'); 
+                            Hot.startLoad() 
+                            editTool.loadDone('data2', e)
                         }
-                        Hot.createHotList();
                         
-                        
-                        if(DATA.roomLabels){
-                            DATA.roomLabels.forEach((data)=>{
-                                this.roomLabels.push(new RoomLabel(data))
-                            })
+                        if(player.currentPano){
+                            create()
+                        }else{
+                            let f = ()=>{
+                                window.bus.removeEventListener('playerAndModelReady',f) 
+                                create() 
+                            }
+                            window.bus.addEventListener('playerAndModelReady',f) 
                         }
                         
                         
-                         
-                        
-                        /* if(e.multiOverlays){
-                            e.multiOverlays.forEach((info)=>{ 
-                                new Hot(info)
-                            })
-                            
-                        }) */
-                       
-                        Hot.startLoad() 
                         
                         e.weixinDesc && (g_weixinObj.desc = e.weixinDesc) 
                          
@@ -17144,21 +17230,27 @@ function o(a, s, l) {
                 this.skybox = new n(this.boundingBox),
                 this.skybox.matrixWorldNeedsUpdate = !0,
                 this.add(this.skybox) 
-                /* setTimeout(function() {
-                    //this.hotsCount && this.shineHots() 
-                    Hot.beginShineHot()
-                    
+                 
+                //因为一部分漫游点在模型外
+                {
+                   
+                    let bounding = new THREE.Box3  //不包含pano的bound
+                    this.floors.list.forEach(floor=>{
+                        bounding.union(floor.conservativeBoundingBox)
+                    })
+                    this.boundWithoutPanos = bounding
+                    this.sizeWithoutPanos = bounding.size()
+                    this.centerWithoutPanos = bounding.center()
+                     
+                    /*  如果想居中模型, bound不加pano:
+                    this.boundingBox = bounding
+                    this.size = bounding.size()
+                    this.center = bounding.center()  */ 
                 }
-                .bind(this), 1300), */
                 
+                     
                 
-                //add-----
-                console.log('计算visiblePanos开始,可能需要一段时间')
-                for(let i in this.hots){
-                    this.hots[i].setVisiblePanos(this.hots[i].info.visiblePanos);
-                } 
-                console.log('计算visiblePanos完毕')
-                //---------   
+                 
                     
                 return R.debug("Done building model"), 
                 0 < f.raycastsDone && (R.warn("raycasts: " + f.raycastsDone),
@@ -17391,7 +17483,7 @@ function o(a, s, l) {
                 throw new o("Tried to activate invalid model!");
             var i = this.activeModel;
             this.activeModel = t,
-            this.tileDownloader.setPanoData(t.panos, t.listImagePanos(), t.sid),
+            this.tileDownloader.setpanoData(t.panos, t.listImagePanos(), t.sid),
             this.tileDownloader.setUrls(t.urls),
             t.panos.forEach(function(e) {
                 e.attachToPanoRenderer(this.panoRenderer),
@@ -18314,8 +18406,8 @@ function o(a, s, l) {
                 return this.position
             }
             ,
-            r.prototype.addTextSprite = function(e, color, parent) {
-                this.removeTextSprite();
+            /*r.prototype.addTextSprite = function(text, color, parent, scale=1) {
+                 this.removeTextSprite();
                 var ratio = 16;
                 var i = document.createElement("canvas")
                   , n = i.getContext("2d");
@@ -18324,6 +18416,7 @@ function o(a, s, l) {
                 n.font = " 30px Arial",
                 n.fillStyle = "white";
                 var r = n.measureText(e).width;
+
                 n.fillText(e, (i.width - r) / 2, (i.height + 60) / 2);
                 var o = new s.Texture(i);
                 o.needsUpdate = !0;
@@ -18341,18 +18434,57 @@ function o(a, s, l) {
                     this.text3d.position.copy(this.skyboxMesh.position)
                     this.floor.add(this.text3d)
                 }
-                
+                 
            
-                
-                var scale = 5
+                 
                 this.text3d.scale.y = scale/ratio
                 this.text3d.scale.x = scale
-            }
-            ,
+                 
+                   
+
+            }  
             r.prototype.removeTextSprite = function() {
                 this.text3d && (this.text3d.parent.remove(this.text3d),
                 this.text3d.material.map.dispose(),
                 this.text3d = null)
+            } */ 
+                
+            r.prototype.addTextSprite = function(text = this.id, color, parent, scale=1) {    
+                this.removeTextSprite()
+                this.label = new TextSprite({ 
+                    /* sizeInfo: {
+                        minSize: 50,
+                        maxSize: 300,
+                        nearBound: 0.2,
+                        farBound: Math.max(20, this.model.size.length() / 3),
+                        farBoundPlan: 250,
+                    }, */ 
+                    renderOrder: 8,
+                    backgroundColor:{r:  255, g: 255, b: 255, a: 0 }, 
+                    textColor: { r: 255, g: 255, b: 255, a: 1 }, 
+                    textshadowColor: '#888',
+                    text,
+                    fontsize: 20*scale,
+                    
+                })
+                if(color){
+                    this.label.children[0].material.color.set(color)
+                } 
+                if(parent){
+                    parent.add(this.label) 
+                    this.label.position.z = 0.1 
+                }else{
+                    let position = this.floorPosition.clone()
+                    position.y += 0.4
+                    this.label.position.copy(position)
+                    this.floor.add(this.label2)
+                } 
+                
+            }
+            ,
+            r.prototype.removeTextSprite = function() {
+                this.label && this.label.dispose()
+    
             }
             ,
             r.prototype.isAligned = function() {
@@ -19001,7 +19133,7 @@ function o(a, s, l) {
                     H.debug('Brushing from "' + this.player.currentPano.id + '" to "' + this.warpDestPano.id + '" (' + (this.nodes ? this.nodes.length : 0) + ")"),
                     n ? (H.info('No "walkable" route, using fall-back warp style transition'),
                     e = t) : (this.setPathHulls(this.nodes),
-                    this.setFloorCurves(),
+                    this.setFloorCurves(), 
                     i && ("chevron" === D.path.style ? this.obj3d.add(this.drawPathPavement(this.floorCurvePoints)) : "ribbon" === D.path.style && this.obj3d.add(this.drawPathRibbon(this.floorCurvePoints, this.floorCurveColors)))),
                     this.player.currentPano.floor.add(this.obj3d);
                     var r = this.player.mode === O.DOLLHOUSE || this.player.mode === O.FLOORPLAN
@@ -19157,6 +19289,15 @@ function o(a, s, l) {
             }
             ,
             t.prototype.drawPathRibbon = function(e, t) {
+                /* let map = Texture.load('images/arrow.png') 
+                map.anisotropy = 4 
+                map.repeat.set(1, 6)
+                map.wrapS = THREE.RepeatWrapping
+                map.wrapT = THREE.RepeatWrapping
+                map.needsUpdate = true
+                 */
+                
+                
                 this.bunnyObj.visible = D.warp.showBunny;
                 for (var i = .6 * D.path.ribbonWidth * .5, n = new P.Vector3, r = new P.Vector3(0,this.pathHeight(),0), o = new P.Geometry, a = new P.Vector3, s = 0; s < e.length; s += 1) {
                     a.copy(e[s]),
@@ -19202,7 +19343,10 @@ function o(a, s, l) {
                     color: 16777215,
                     side: P.DoubleSide,
                     name: "ribbonOut",
-                    vertexColors: P.VertexColors
+                    vertexColors: P.VertexColors,
+                    
+                    /* transparent:true,
+                    map */
                 });
                 var y = new P.Mesh(o,h);
                 return y.name = "ribbon",
@@ -19817,11 +19961,15 @@ function o(a, s, l) {
             ,
             t.prototype.warpTravel_BLACK = function(e, t, i, n) {
                 var r = e || 0;
-                null != t || (t = D.warp.teleportTime) 
+                null !=
+                t || (t = D.warp.teleportTime) 
                 //add
-                var done = ()=>{ 
-                    Hot.updateVisibles([this.player.currentPano]) //更新热点显示
-                    this.player.transitionPos({type:"beforeFlytopano", pano:this.player.currentPano, dur:100})//add 
+                player.model.hotGroup.visible = false
+                var done = ()=>{   
+                    this.player.transitionPos({type:"beforeFlytopano", pano:this.player.currentPano, dur:0, callback:()=>{
+                        player.model.hotGroup.visible = true
+                        Hot.updateVisibles([this.player.currentPano]) //更新热点显示 
+                    }}) 
                    
                 }
                 if(window.DATA.momentTourBlackNewType){
@@ -20943,7 +21091,7 @@ function o(a, s, l) {
                         return;
                     }
                     if (window.VisiSet && VisiSet.setTagVisible ) { 
-                        VisiSet.tagVsetting && this.intersect && this.intersect.object.visible && VisiSet.dealTagVisible(VisiSet.tagVsetting, this.intersect.object.name);
+                        VisiSet.tagVsetting && this.intersect && this.intersect.object.visible && VisiSet.dealTagVisible(this.intersect.object.name);
                         return;
                     }
                     if (window.VisiSet && VisiSet.setPanoLog ) { 
@@ -20954,6 +21102,10 @@ function o(a, s, l) {
                         this.intersect && this.intersect.object.visible && VisiSet.dealRouteClick(this.intersect.object);
                         return;
                     }
+                    if (window.VisiSet && VisiSet.setPanoArea ) { 
+                        this.intersect && this.intersect.object.visible && VisiSet.dealPanoAreaClick( this.intersect.object);
+                        return;
+                    }
                     if(this.hoveringPlane){
                         this.clickOverlay(this.hoveringPlane)
                         return;
@@ -21215,12 +21367,21 @@ function o(a, s, l) {
                     if (position) {
                         camera.position.copy(position)
                     }
-                    if(mode == V.DOLLHOUSE){
-                    
-                        var o = this.position.clone();
-                        this.mode === V.PANORAMA ? o.add(new B.Vector3(0,6,0)).add(this.getDirection().multiplyScalar(-10)) : o.add(T.DOWN.clone().applyQuaternion(this.quaternion).multiplyScalar(6)).setY(6),
-                        camera.position.copy(o),
-                        control.target.copy(this.target.clone().setY(this.model.center.y));
+                    if(mode == V.DOLLHOUSE){ 
+                        var pos = this.position.clone();
+                        if(this.mode === V.PANORAMA){ 
+                            let vec = new B.Vector3(0,6,0).add(this.getDirection().multiplyScalar(-10))
+                            if(target)vec.multiplyScalar(0.15) //编辑热点时飞出不要飞太远,只是飞出来就近观察一下热点
+                            pos.add(vec) 
+                        }else{
+                            pos.add(T.DOWN.clone().applyQuaternion(this.quaternion).multiplyScalar(6)).setY(6)  
+                        } 
+                        
+                        camera.position.copy(pos)  
+                        if(!target) target = this.target.clone().setY(this.model.center.y)
+                        control.target.copy(target);
+                          
+                         
                          
                         //for多楼层 且 让模型刚好适应屏幕
                         
@@ -21481,12 +21642,12 @@ function o(a, s, l) {
                     } 
                 }
                 
-                if (window.VisiSet && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog || VisiSet.setRoute )) {
+                if (window.VisiSet && (VisiSet.setPanoVisible || VisiSet.setTagVisible || VisiSet.setPanoLog || VisiSet.setPanoArea && VisiSet.editPanoArea || VisiSet.setRoute )) {
                     let meshes = this.model.hotGroup.children.slice()
                     if(VisiSet.routeInfo?.operation == 'removeLink'){
                         meshes.push(...VisiSet.meshGroup.children.filter(e=>e.name.includes('routeLine:')))
                     }else{
-                        meshes.push(...VisiSet.footIcons)
+                        VisiSet.footIcons && meshes.push(...VisiSet.footIcons)
                     }
                     
                     
@@ -21980,7 +22141,7 @@ function o(a, s, l) {
             window._transitionPosId = 9999
             
             t.prototype.transitionPos = function(o={}) {//渐变overlay和热点的位置
-             
+         
                 G.cancelById(_transitionPosId)
                   
                 var begin = function(object, pos, qua, scale){ 
@@ -21988,7 +22149,7 @@ function o(a, s, l) {
                         if(!same(object.position, pos, 0.01)){
                               
                             G.start(H.vector(object.position, pos), o.dur, (e)=>{
-                                
+                                object.updateScale()
                             },0, z[k.transition.movementEasing], "transitionPos", _transitionPosId)
                         }    
                         
@@ -22014,20 +22175,7 @@ function o(a, s, l) {
                     return s
                 }
                 var sid = o.pano != void 0 ? o.pano.id : "outside";
-                /* this.model.hotGroup.children.forEach(overlay=>{ 
-                    var panoData = overlay.transformAtPanos[sid]
-                    var useCustom = !panoData
-                    //if(overlay.usingTransformData || !useCustom){
-                        var pos = useCustom ? overlay.posCustom : panoData.pos;
-                        var qua = useCustom ? overlay.quaCustom : panoData.qua;
-                        var scale = useCustom ? overlay.getScaleBySize(overlay.widthCustom, overlay.heightCustom) :  
-                                    overlay.getScaleBySize(panoData.width , panoData.height)
-                            scale = new THREE.Vector3(scale.x, scale.y, overlay.scale.z)        
-                        begin(overlay, pos, qua, scale  )
-                    //}
-                    overlay.usingTransformData = !useCustom
-                }) */
-                
+                 
                 
                 for(let i in this.model.hots){//是否判断visible?
                     var hot = this.model.hots[i];
@@ -22043,6 +22191,12 @@ function o(a, s, l) {
                     //hot.usingTransformData = !useCustom;
                 }
             
+                if(o.callback){
+                    setTimeout(()=>{
+                        o.callback()
+                    },o.dur + 16) ;//姑且这么写
+                }
+            
             }
             
             
@@ -22052,15 +22206,16 @@ function o(a, s, l) {
             t.prototype.focusPoint = function(o={}){//当在外时,聚焦相机到这一点 
                 //console.log("focusPoint")
                 if(this.mode == "floorplan"){
-                    var modelSize = o.modelSize || new THREE.Vector3(8,8,8);//可视范围
                     var control = player.cameraControls.controls.floorplan;
-                    var absoluteScale = control.getDefaultAbsoluteScale(modelSize)
-                    var currentScale = control.absoluteScale;
                     var currentTarget = control.target.clone()
-                        
+                    if(!o.dontChangeScale){
+                        var modelSize = o.modelSize || new THREE.Vector3(8,8,8);//可视范围 
+                        var absoluteScale = control.getDefaultAbsoluteScale(modelSize)
+                        var currentScale = control.absoluteScale; 
+                    }
                     G.cancelById(window._tranOutsideFocus, true);
                     G.start(function(progress){ 
-                        control.absoluteScale = absoluteScale*progress + currentScale*(1-progress);
+                        o.dontChangeScale || (control.absoluteScale = absoluteScale*progress + currentScale*(1-progress))
                         control.target = o.aim.clone().multiplyScalar(progress).add(currentTarget.clone().multiplyScalar(1-progress))
                         control.camera.position.copy(control.target.clone().add(control.offset)) //维持角度
                     }.bind(this) , o.dur || 600, null/* cancelFuc */, 0, z[k.transition.movementEasing], "outsideFocus", window._tranOutsideFocus, null/* cancelFuc */);	 
@@ -22734,10 +22889,10 @@ function o(a, s, l) {
                         rotTime = defaultRotTime
                     } 
                     rotTime = Math.max(0, rotTime)
-                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem + (hasMusic ? (",musicCurrentTime:"+current+'音乐总长:'+currentLocation0.musicInfo.time) : '')) 
+                    //console.log("rotTime "+rotTime +" at item "+this.director.currentItem + (hasMusic ? (",musicCurrentTime:"+current+'音乐总长:'+currentLocation0.musicInfo.time) : '')) 
                 }else{
                     rotTime = currentLocation.rotTime * 1000
-                    console.log("rotTime "+rotTime +" at item "+this.director.currentItem) 
+                    //console.log("rotTime "+rotTime +" at item "+this.director.currentItem) 
                 }
                  
                 this.path.waitNextStep(e, function() {//等待音乐播放一段时间再下一步,此时镜头会缓慢旋转
@@ -26739,6 +26894,7 @@ function o(a, s, l) {
             this.useHighResolutionPanos = !0,
             this.useUltraHighResolutionPanos = !1,
             this.modelHasUltraHighPanos = !1
+            this.maxRenderTargetSize = Math.min( common.getMaxCubemapSize(),  this.maxRenderTargetSize)//add
         }
         var r = e("../enum/PanoSizeClass")
           , o = e("../settings")
@@ -26885,7 +27041,7 @@ function o(a, s, l) {
                 this.urls = e
             }
             ,
-            i.prototype.setPanoData = function(e, t, i) {
+            i.prototype.setpanoData = function(e, t, i) {
                 this.panos = e,
                 this.imagePanos = t,
                 this.panoGroupId = i
@@ -29573,7 +29729,7 @@ function o(a, s, l) {
     }],
     188: [function(e, t, i) {
         "use strict";
-        t.exports = {
+        window.lerp = t.exports = {
             vector: function(t, i) {
                 var n = t.clone();
                 return i = i.clone(),

文件差異過大導致無法顯示
+ 497 - 143
js/main_2020_show.js


+ 219 - 100
js/manage.js

@@ -145,6 +145,11 @@ var settings = {
             max: browser.urlHasValue('phoneMax',true) || '4k',  //放到最大
         }
     }, //可以稍后自行修改
+    
+    /* extractFloor : { //提取一部分chunk作为新的floor,该floor不在楼层列表里显示,一般用于飞出后隐藏屋顶
+        'KJ-t-tHpdpKvb0ew' : [1,2,3,4,5,6,7,8], //第0层的第1,2,3个chunk是屋顶 
+    } */
+    
 }
 
 
@@ -697,7 +702,23 @@ window.expandCommon = function(common){
             }
 
             return v
-        } 
+        },
+         
+        getMaxCubemapSize() {//在renderer创建完前获取
+            let size = player.sceneRenderer?.renderer?.capabilities.maxCubemapSize
+            if(size){
+                return size
+            }
+            try {
+                var e = document.createElement('canvas'),
+                    t = e.getContext('webgl')
+                t || (t = e.getContext('experimental-webgl'))
+                var i = t.getParameter(t.MAX_CUBE_MAP_TEXTURE_SIZE)
+                return i
+            } catch (e) {
+                return 0
+            }
+        }
     })
     
 }
@@ -727,7 +748,25 @@ window.expandMath = function(math){
                 }
             }
             return value
-        }
+        },
+        
+        
+        getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) .  Math.log 返回一个数的自然对数
+            return Math.log(y) / Math.log(x);
+        },
+        
+        getSpreadRatio(n){//n为整数,返回的0-1的数。 目的是获得较为平均的数字,主要用于颜色hue。数字含义:按顺序将1不停平分下去,每刀都切在每段的二分之一处,则第n刀在原先整体的几分之几处
+            if(n==0)return 0  
+            let k = Math.floor(math.getBaseLog(2,n)) //是2的几次幂
+            let r = ((n - Math.pow(2,k) ) * 2 + 1)/ Math.pow(2,k+1) 
+            console.log('getSpreadRatio',n,r)  
+            return r
+        } 
+        
+        
+       
+        
+        
     })
 }
 
@@ -1372,12 +1411,12 @@ function initByTHREE(THREE){
             //draw coverTex
             this.quad.material.uniforms.progress.value = 1;
             sceneRenderer.renderer.render( sceneRenderer.scene, sceneRenderer.camera, this.coverRenderTarget, true );
-            console.log('start111')
+            
             
         },
         stop:function(){
             this.enabled = false
-            console.log('stop111')
+          
         }
         ,
         
@@ -1635,9 +1674,21 @@ function initByTHREE(THREE){
                 let result = common.sortByScore(player.model.floors.index[this.floorIndex].panos, [], [(pano)=>{
                     return -pano.position.distanceToSquared(this.position)
                 }]);
-                player.flyToPano({ 
-                    pano : result && result[0] && result[0].item
-                })
+                let pano = result && result[0] && result[0].item
+                if(pano){
+                    const minDisSquard = 200
+                    if(pano.position.distanceToSquared(this.position) > minDisSquard){
+                        pano = null
+                    }
+                }
+                
+                if(pano){
+                    player.flyToPano({ 
+                        pano  
+                    })
+                }else{
+                    player.focusPoint({aim: this.position, radius: 20, dur:1000})
+                }
             }
              
             super(o)
@@ -1775,7 +1826,6 @@ function initByTHREE(THREE){
             super()
             let map = new THREE.Texture()
             this.root = options.root || this
-            //if (options.fixOrient) {
             this.sprite = new THREE.Mesh(
                 planeGeo,
                 new THREE.MeshBasicMaterial({
@@ -1786,17 +1836,7 @@ function initByTHREE(THREE){
                     depthWrite: false,
                 })
             )
-            /*}  else {
-                this.sprite = new THREE.Sprite(
-                    new THREE.SpriteMaterial({
-                        map,
-                        color: 0xffffff,
-                        transparent: true,
-                        depthTest: false,
-                        depthWrite: false,
-                    })
-                )
-            } */
+           
 
             this.add(this.sprite)
             this.sprite.renderOrder = options.renderOrder != void 0 ? options.renderOrder : 2
@@ -1812,10 +1852,10 @@ function initByTHREE(THREE){
             this.borderRadius = options.borderRadius == void 0 ? 6 : options.borderRadius
             this.margin = options.margin
             this.textshadowColor = options.textshadowColor
-            if (options.text != void 0) this.setText(options.text)
+            
             this.name = options.name
             this.sizeInfo = options.sizeInfo
-            //this.setText(text);
+          
             
             this.addEventListener('dispose', this.dispose.bind(this))
             this.fixOrient = options.fixOrient
@@ -1832,7 +1872,14 @@ function initByTHREE(THREE){
                 }
             })
 
-            this.updatePose()
+             
+            
+            if (options.text != void 0) this.setText(options.text)
+                
+            setTimeout(()=>{
+                this.updatePose()
+            },1)
+            
         }
  
                  
@@ -1966,7 +2013,7 @@ function initByTHREE(THREE){
                     context.shadowOffsetX = 0
                     context.shadowOffsetY = 0
                     context.shadowColor = this.textshadowColor
-                    context.shadowBlur = 12
+                    context.shadowBlur = 0.3 * this.fontsize
                 }
                 context.fillText(this.text[i], x, y)
 
@@ -2141,8 +2188,9 @@ function initByTHREE(THREE){
             transparent:true,
             map:arrowTex,
             side:2,
-            opacity: arrowInfo.maxOpa
+            opacity: arrowInfo.maxOpa,
             //depthTest:false
+            depthWrite:false, //防止和导览路线重叠闪烁
         }) 
         let mats = {
             default: arrowMat,
@@ -2192,7 +2240,7 @@ function initByTHREE(THREE){
             while(i>0){
                 
                 let pos = from.floorPosition.clone().add(dir.clone().multiplyScalar(margin/2 + i*sliceLen))
-                    pos.y+=settings.markerHeight
+                    pos.y+=settings.markerHeight 
                 let arrow = createArrow(mat)
                     arrow.name = 'arrow:'+from.id+"-"+to.id+"|"+i
                 arrow.rotation.set(Math.PI/2, 0, angle);
@@ -2236,14 +2284,14 @@ function initByTHREE(THREE){
 
         var lastArrowPanos = []
         var updateArrow = function(){//根据当前pano更新
-            //console.log(currentPano)
+            
             if(player.mode != 'panorama' || hide){ //飞出 
                 arrows.visible = false           
                 lastArrowPanos = []
                 return;
             }
             arrows.visible = true
-            currentPano = player.currentPano
+            let currentPano = player.currentPano
             
             
             //先获取所有需要箭头的pano
@@ -2261,12 +2309,12 @@ function initByTHREE(THREE){
             var search = function(pano, path=[pano], angles=[]){//多分支搜寻
                 
                 var neighbor = panos.routeNextMap[pano.id];
-                if(!neighbor || !neighbor.length)return path.length>1 && console.log('branchPath',path);
+                if(!neighbor || !neighbor.length)return //path.length>1 && console.log('branchPath',path);
                 
                 
                 neighbor.forEach(e=>{
                     let branchPath = path.slice(), angles_ = angles.slice() 
-                    if(panos_.find(arr=>arr[0]==e))return console.log('不回头branchPath',branchPath); //不回头
+                    if(panos_.find(arr=>arr[0]==e))return //console.log('不回头branchPath',branchPath); //不回头
                     dis = e.floorPosition.distanceTo(currentPano.floorPosition)
                     
                     branchPath.push(e)
@@ -2283,7 +2331,7 @@ function initByTHREE(THREE){
                             let angleDiff = Math.abs(( lastAngle - angle) % (Math.PI*2) ) //越远限制越大
                             let minDiff = math.linearClamp(branchPath.length,[3,6],[0.2,0.5])
                             if(Math.abs(angleDiff - Math.PI ) < minDiff){
-                                console.log('因为折回而提前结束', n, branchPath)
+                                //console.log('因为折回而提前结束', n, branchPath)
                                 return true
                             } 
                         })
@@ -2296,7 +2344,9 @@ function initByTHREE(THREE){
                     if(branchPath.length<3 || dis < maxDistance){
                         panos_.push([pano, e]) 
                         search(e, branchPath, angles_)
-                    }else console.log('branchPath',branchPath)
+                    }else{
+                        //console.log('branchPath',branchPath)
+                    }
                 })
                 
             }
@@ -2385,6 +2435,10 @@ function initByTHREE(THREE){
         let f = ()=>{
             window.bus.removeEventListener('playerAndModelReady',f)
              
+             
+               
+             
+             
             player.on("mode.changing",(currentMode, mode, pano, duration)=>{ 
                 let noLine = mode == 'floorplan';
                 if(noLine){
@@ -2437,24 +2491,72 @@ function initByTHREE(THREE){
                 player.model.floors.add(roof)
                 player.model.floors.list[0].chunks.splice(1,1) 
             }  */
+     
+                
+            if(settings.extractFloor){ 
+                let data = settings.extractFloor[number]
+                if(data){ 
+                    setTimeout(()=>{
+                        let roof = new player.model.floors.list[0].constructor(player.model, player.model.floors.length);//放在第三层 隐藏起来
+                        roof.build()
+                        player.model.floors.add(roof)
+                        
+                        for(let i=0;i<data.length;i++){
+                            let chunk = player.model.chunks[data[i]]
+                            let oldFloor = chunk.parent
+                            roof.addChunk(chunk)
+                            let index = oldFloor.chunks.indexOf(chunk)
+                            oldFloor.chunks.splice(index,1)
+                        } 
+                    },10)
+                    
+                } 
+                
+            }
             
             
-            
-            /* if(number == 'SG-LF0SeEdxWjv' || number == 'SG-mBoheb4MAIb' || number == 'SG-H5A4vvPXqsE'){//在展示第一层时需要隐藏屋顶
+            {//根据漫游点切换音频
+                let curAudio  
+                let bgmObject = SoundManager.list.find(e=>e.name == 'bgm')
+                let setCurBgm = (pano)=>{
+                    if(!window.DATA.panoAreas)return
+                    let item = window.DATA.panoAreas.find(e=>e.panos.some(a=>a == pano.id))
+                    let areaAudio = item?.audio && item.audio[1]
+                    if(areaAudio != curAudio ){   
+                        let canPlay = !bgmObject.audio.paused || bgmObject.canplay() && !(SoundManager.currentAudio && SoundManager.currentAudio != bgmObject && SoundManager.currentAudio.src) //没有其他音频在播放的话就可以播      //!pl
+                        SoundManager.setSrc('bgm', areaAudio || window.DATA.backgroundMusic, areaAudio ? (item.name +':'+item.audio[0]) : '全局背景音') 
+                        curAudio = areaAudio
+                         
+                        if(canPlay){
+                            SoundManager.play('bgm')
+                            $("#volume").show();
+                        }
+                        
+                        if(areaAudio || window.DATA.backgroundMusic){
+                            $("#volume").show()
+                        }else{
+                            $("#volume").hide()
+                        }
+                        
+                    }
+                }
+                player.on("flying.ended",(a,b,pano,d)=>{
+                    pano && setCurBgm(pano) 
+                })
                 
-                let [roofFloorIndex,roofChunkIndex] = ({
-                    'SG-LF0SeEdxWjv' : [0,1], //第0层的第1个chunk是屋顶
-                    'SG-mBoheb4MAIb' : [0,3],
-                    'SG-H5A4vvPXqsE' : [0,3],
-                })[number]
-                  
-                let roof = new player.model.floors.list[0].constructor(player.model, 2);//放在第三层 隐藏起来
-                roof.build()
-                roof.addChunk(player.model.floors.list[roofFloorIndex].chunks[roofChunkIndex])
-                player.model.floors.add(roof)
-                player.model.floors.list[roofFloorIndex].chunks.splice(roofChunkIndex,1)
                 
-            } */
+                manage.addEventListener('pauseSound',(e)=>{
+                    if(SoundManager.playHistory.length == 0 && e.object != bgmObject){//其他都停了的话
+                        //console.log('SoundManager.playHistory.length == 0')
+                        setCurBgm(player.currentPano) 
+                    }
+                })
+                
+                
+                player.currentPano && setCurBgm(player.currentPano)
+                
+                 
+            }
         } 
         
         
@@ -2471,7 +2573,55 @@ function initByTHREE(THREE){
  
  
  
+{
  
+    let infoPannel = $('<div id="alert" class="closed"><div name="content"></div><div class="close"></div></div>')
+    $('body').append(infoPannel)
+    
+    let showDur;
+    
+    let close = ()=>{
+        infoPannel.addClass('closed')
+        clearTimeout(timer)
+        timer = null
+    }
+    let timer, currName;//定时器
+    
+    infoPannel.find('.close').on('click',close);
+    
+    window.alertInfo = function(text, {dur, dontAutoClose, hideCloseBtn, name}={}){
+        if(timer){
+            clearTimeout(timer)
+        }
+        
+        infoPannel.find('[name=content]').html(text)
+        
+        infoPannel.removeClass('closed')
+        
+        
+        if(hideCloseBtn){
+            infoPannel.find('.close').addClass('hide')
+        }else{
+            infoPannel.find('.close').removeClass('hide')
+        }
+        
+        
+        showDur = dur || (1500 + Math.round(text.length * 20))
+        if(!dontAutoClose){
+            timer = setTimeout(close, showDur) 
+        }
+        currName = name
+
+    }
+    
+    
+    
+    window.alertClose = function(name){
+        if(currName == name){
+            close()
+        }
+    }
+}
  
  
  
@@ -2489,9 +2639,7 @@ function initByTHREE(THREE){
 //最好能知道应该播放到的currentTime
 var SoundManager = {//暂不支持同时播放
     currentAudio:null,//当前正在播放list中的哪一个
-    enableSound:true,//是否允许有声音
-    
-    
+    enableSound:true,//是否允许有声音 
     playHistory:[],//被打断的加入播放历史
     
     list:[ ],//同一级别可以互相打断 //暂时不做多级别
@@ -2538,10 +2686,10 @@ var SoundManager = {//暂不支持同时播放
             this.currentAudio = null
             
             
-            if(object.audio){
+            if(object.audio){  
+                !object.audio.paused && Log(name + ' 中断音频 '+  "("+common.getFileNameFromUrl(object.audio.src)+')' )
                 object.audio.pause()
                 object.callback && object.callback(false)
-                object.audio.src && Log(name + ' 中断音频 '+  "("+common.getFileNameFromUrl(object.audio.src)+')' )
             }
             
             
@@ -2559,21 +2707,20 @@ var SoundManager = {//暂不支持同时播放
                     }
                     
                 }
-                
             }
             
-            
+            manage.dispatchEvent({type:'pauseSound', object})
         }
         
     },
     
  
     
-    setSrc : function(name, src){//不能直接给audio赋src!一定要用这个函数!因为我要拿这里的src来判断有无src,因为貌似audio的src会自动变,''时会变成html的链接
+    setSrc : function(name, src='', desc=''){//不能直接给audio赋src!一定要用这个函数!因为我要拿这里的src来判断有无src,因为貌似audio的src会自动变,''时会变成html的链接
         var object = this.list.find(e=>e.name == name)
         object.src = src
         object.audio.src = src
-        Log(`${object.name} 设置src: ${src}`)
+        Log(`${object.name} ${desc} 设置src: ${src} `)
     },
     
     createAudio:function(object={}){//name, level, canplay
@@ -2594,7 +2741,7 @@ var SoundManager = {//暂不支持同时播放
             
             
             object.audio.oncanplaythrough = ()=>{ 
-                Log(`${object.name} canplaythrough  `) 
+                //Log(`${object.name} canplaythrough  `) 
             }
         }
         
@@ -2613,7 +2760,7 @@ var SoundManager = {//暂不支持同时播放
                  
                 this.currentAudio.callback && this.currentAudio.callback(true)
                 
-                Log(`${this.currentAudio.name} 自动播放成功`) //即使设置src在这之后好像也能成功播放
+                Log(`${this.currentAudio.name} 自动播放`) //即使设置src在这之后好像也能成功播放
             }else{
                 
             }
@@ -2644,10 +2791,7 @@ function Log(value, color, fontSize){
 
 
 Manage.prototype.loadAudio = function() { //相关:g_tourAudio \  g_playAudio
-    
-     
-    
-    
+      
     //热点页面因为挡住了界面,所以暂时不存在别的音频阻止热点音频的可能
     //box视频都静音,所以暂时不考虑
     
@@ -2681,14 +2825,23 @@ Manage.prototype.loadAudio = function() { //相关:g_tourAudio \  g_playAudio
     SoundManager.createAudio({
         name:'hot',
         fake:true,//实际上没有audio. 只是为了来停止和续播其他音频
-        level:1, 
+        level:2, 
         src:'',
         loop:false,
         canplay:(audio)=>{
             
         }
     })
-     
+    /* SoundManager.createAudio({//区域bgm  //暂定背景音乐按钮 同时控制整体和局部的播放。之后可能会改成仅单独控制bgm,或者分为两个按钮,需要再createAudio。
+        name:'pano', 
+        level:1, 
+        src:'',
+        loop:true,
+        canplay:(audio)=>{
+            return true
+        }
+    }) */
+    
     
     $("#volume").find("a").on("click", ()=> {  
         if($("#volume img")[0].src.indexOf("btn_on.png")>-1)
@@ -2711,50 +2864,16 @@ Manage.prototype.loadAudio = function() { //相关:g_tourAudio \  g_playAudio
  
 Manage.prototype.switchBgmState = function(state){//按钮的状态完全代表是否应该播放bgm,即使还没加载完
     this.bgmShouldPlay = state
-    
-    
-    if(state){
-        
+     
+    if(state){ 
         SoundManager.play('bgm')
-    }else{
-        
+    }else{ 
         SoundManager.pause('bgm')
     }
     
     this.dispatchEvent && this.dispatchEvent({type:'switchBgmState'})
     
-    /* if(!g_bgAudio || !g_bgAudio.src) return;
-    
-    
-    var played = function(){
-        console.log('begin play bgm');
-        g_play = 1; 
-        g_playAudio = g_bgAudio;
-        
-        g_tourAudio && g_tourAudio.pause()
-    }
-    var paused = function(){ 
-        g_play = 0;
-        g_playAudio == g_bgAudio && (g_playAudio =  null)
-        
-    }
-    
-    if(state ){
-        g_bgAudio.play(); 
-        if(g_bgAudio.paused){
-            paused()
-        }else{
-            played()
-            return true
-        }            
-    }else{
-        g_bgAudio.pause();
-        paused()
-    } 
-    
     
-    g_bgAudio.pauseByHot = false
-    g_bgAudio.pauseByTour = false */
 }    
 
 var manage = new Manage();
@@ -2891,7 +3010,7 @@ function logSth(){
 
 /* let kankanNames = ['SG-','KJ-'] */
 
-window.sceneFrom = (number.length > 6 && number.slice(0,3).includes('-')) ? 'kankan' : '' //看看or看见转来的
+window.sceneFrom = (number.length > 6 && number.slice(0,3).includes('-') || browser.urlHasValue('kankan') ) ? 'kankan' : ''  //看看or看见转来的
 
 //兼容一代的場景
 //請求地址統一管理