Hot.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748
  1. //合并热点和展览
  2. g_currentHot = null
  3. window.initHot = function (model) {
  4. var objLoader = new THREE.OBJLoader()
  5. var _planeGeometry = new THREE.PlaneGeometry(1, 1)
  6. var _boxGeometry = new THREE.BoxBufferGeometry(1, 1, 1)
  7. {//ie的mesh 加了polygonOffset也是会重叠。所以去掉前面的face: (但是突然ie又播放不了videoTexture)
  8. var newIndex = [..._boxGeometry.index.array]
  9. newIndex.splice(4 * 6, 12)
  10. _boxGeometry.setIndex(new THREE.BufferAttribute(new Uint16Array(newIndex), 1))
  11. }
  12. var originPhotoCount = photoLoaded = originModelCount = modelLoaded = 0
  13. var defaultTex1 = Texture.load(g_HotImage.point)
  14. var defaultTex2 = Texture.load(g_HotImage.point2)
  15. /* var _boxMat = new THREE.MeshBasicMaterial({
  16. color: "#eeeeee",
  17. transparent: !0,
  18. opacity: 0.8
  19. }) */
  20. var _boxMat = new THREE.MeshPhongMaterial({
  21. color: "#eeeeee",
  22. transparent: !0,
  23. opacity: 0.8,
  24. side: THREE.DoubleSide
  25. })
  26. var autoSizeInfo = { minSize: 120, maxSize: 600, nearBound: 1, farBound: 15 }
  27. var hotGroup = new THREE.Object3D; hotGroup.name = "hotGroup"
  28. model.add(hotGroup); model.hotGroup = hotGroup
  29. var animateTexSrcs = {}
  30. var getCommonHotspotUrl = function (link) {
  31. var querySectionInLink = link.split('?')[1]
  32. return `https://www.4dmodel.com/SuperTwo/hot_online1/index.html#/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}`
  33. // var langParam = "en" == manage.number("lang") ? "&lang=" + manage.number("lang") : ""
  34. // return `http://192.168.20.16:8083/#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
  35. // return `../hotspot/index.html#/${browser.isMobile() ? 'mobile' : 'web'}/?${querySectionInLink}&time=${randomTime().getTime()}&id=${window.number}${langParam}`
  36. }
  37. var removeSrcPostMark = function (url) {//去除texture.load时自动加上的'?'
  38. var index = url.indexOf('?')
  39. if (index > -1) {
  40. return url.slice(0, index)
  41. } else return url
  42. }
  43. {//get plane Bound
  44. var planeBound = new THREE.Box3()
  45. var cornerPoint = [
  46. new THREE.Vector3(-0.5, 0.5, 0),
  47. new THREE.Vector3(0.5, 0.5, 0),
  48. new THREE.Vector3(0.5, -0.5, 0),
  49. new THREE.Vector3(-0.5, -0.5, 0),
  50. ]
  51. cornerPoint.forEach(e => {
  52. planeBound.expandByPoint(e)
  53. })
  54. }
  55. var shineMats = []
  56. var getShineMat = function (texture1, texture2) {
  57. var mat = shineMats.find(e => e.uniforms.texture1.value == texture1 && e.uniforms.texture2.value == texture2)
  58. if (mat) return mat
  59. else {
  60. var mat = new THREE.ShaderMaterial({
  61. uniforms: {
  62. color: {
  63. type: "c",
  64. value: new THREE.Color(16720384)
  65. },
  66. opac: {
  67. type: "f",
  68. value: 0
  69. },
  70. texture1: {
  71. type: "t",
  72. value: texture1
  73. },
  74. texture2: {
  75. type: "t",
  76. value: texture2
  77. }
  78. },
  79. vertexShader: "varying vec2 vUv;\n\nvoid main() {\n\n vUv = uv ;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n}\n",
  80. fragmentShader: "varying vec3 vNormal;\n\nvarying vec2 vUv;\n\nuniform float opac;\n\nuniform vec3 color;\n\nuniform sampler2D texture1;\n\nuniform sampler2D texture2;\n\nvoid main() {\n\nvec4 tcolor1 = texture2D( texture1, vUv );\n\nvec4 tcolor2 = texture2D( texture2, vUv );\n\ngl_FragColor = mix(tcolor1,tcolor2 ,opac) + tcolor2*0.2; }\n"
  81. , transparent: !0
  82. })
  83. shineMats.push(mat)
  84. return mat
  85. }
  86. }
  87. var modelGeos = []
  88. var getModelGeo = function (url) {
  89. var geo = modelGeos.find(e => e.url = url)
  90. if (geo) return geo
  91. else {
  92. var geo = null
  93. geo.url = url
  94. }
  95. }
  96. class Hot extends THREE.Object3D {
  97. constructor(info, source) {
  98. super()
  99. this.sid = info.sid
  100. this.preDeal(info, source)// source:来源
  101. this.info = info
  102. this.cornerPoints = []
  103. this.build(info)
  104. this.name = "hot_" + this.sid
  105. model.hots[info.sid] = this
  106. }
  107. build(info) {
  108. /* this.changeMaterial(new THREE.MeshBasicMaterial({
  109. color: "#00c8af",
  110. opacity: 0.4,
  111. transparent: !0,
  112. polygonOffset: true,
  113. //是否开启多边形偏移 //ie不开启时blank也不会闪烁
  114. polygonOffsetFactor: -0.9,
  115. //多边形偏移因子
  116. polygonOffsetUnits: -4.0,
  117. //多边形偏移单位
  118. }))
  119. if(!info.objSrc){
  120. this.addPlane()
  121. if (info.hasBox) this.addBox(true)
  122. }else{
  123. this.addModel(new THREE.Mesh())//暂时创建个空的
  124. } */
  125. hotGroup.add(this)
  126. this.setTitleElem()
  127. this.setFromInfo(info)
  128. }
  129. setFromInfo(info, media, objObject) {
  130. //1 恢复到编辑之前 2 初始加载
  131. var plane = this.plane
  132. /* var transformAtPanos = {}
  133. for(var i in info.transformAtPanos){
  134. transformAtPanos[i] = {//只保留一个位移,主要原因是大小变化和热点大小设置冲突了, isSprite和qutaernion衝突
  135. pos : info.transformAtPanos[i].pos && info.transformAtPanos[i].pos.clone(),
  136. //qua : info.transformAtPanos[i].qua && info.transformAtPanos[i].qua.clone(),
  137. }
  138. }
  139. this.transformAtPanos = transformAtPanos */
  140. //在每个漫游点独立设置的position。
  141. var curPanoTransform = this.info.transformAtPanos[getTransformSid()] || {}
  142. //没有单独设置position的漫游点使用的position
  143. this.position.copy(curPanoTransform.pos || info.position)
  144. this.rotation.copy(info.rotation)
  145. this.scale.copy(info.scale)
  146. this.changeTexType(info.texType, media)
  147. if (!info.objSrc) {
  148. this.addPlane()
  149. if (!!this.hasBox != !!info.hasBox) {
  150. this.addBox(!this.hasBox)
  151. }
  152. } else {
  153. this.addModel(objObject || new THREE.Mesh())//暂时创建个空的
  154. }
  155. this.updateMatrixWorld()
  156. /* if(!this.info.visiblePanos){//移到model.build时,在collider建好之后
  157. this.getVisiblePanos()
  158. } */
  159. {//gif
  160. if (this.animation) {
  161. GifTexDeal.remove(this.animation)
  162. }
  163. if (this.info.animateInfo && this.material_.map) {
  164. this.animation = GifTexDeal.addAnimation(this.material_.map, this, this.info.animateInfo, this.sid)
  165. this.visible && this.inSight() && GifTexDeal.start(this.animation)
  166. }
  167. }
  168. /* if(this.info.modelBound){
  169. this.mesh.updateMatrixWorld()
  170. this.mesh.boxHelper2 = new THREE.Box3Helper( new THREE.Box3().copy(this.info.modelBound.bound).applyMatrix4(this.mesh.matrixWorld), new THREE.Color("#00aaee"));
  171. model.add(this.mesh.boxHelper2)
  172. }else{
  173. var bound = new THREE.Box3()
  174. var cornerPoint = [
  175. new THREE.Vector3(-0.5, 0.5, 0),
  176. new THREE.Vector3(0.5, 0.5, 0),
  177. new THREE.Vector3(0.5, -0.5, 0),
  178. new THREE.Vector3(-0.5, -0.5, 0),
  179. ]
  180. cornerPoint.forEach(e=>{
  181. bound.expandByPoint(e)
  182. })
  183. this.mesh.updateMatrixWorld()
  184. this.mesh.boxHelper2 = new THREE.Box3Helper( bound.applyMatrix4(this.mesh.matrixWorld), new THREE.Color("#00aaee"));
  185. model.add(this.mesh.boxHelper2)
  186. } */
  187. }
  188. changeTexType(texType, media) {
  189. var plane = this.plane
  190. if (this.texType != texType || media == 'clear') {
  191. //删除旧的
  192. if (this.texType == 'shine') {
  193. /* this.material_.uniforms.texture1.value.dispose()
  194. this.material_.uniforms.texture2.value.dispose() */ //为了恢复 不删
  195. } else {
  196. //this.material_.map.dispose()
  197. if (this.texType == 'video') {
  198. this.texMedia && this.texMedia.pause()
  199. } else {
  200. }
  201. }
  202. if (this.material_ && !hotGroup.children.find(e => e != this && e.material_ == this.material_)) {
  203. this.material_.dispose()
  204. }
  205. //添加新的
  206. if (texType == 'shine') {
  207. } else {
  208. this.changeMaterial(new THREE.MeshBasicMaterial({
  209. color: "#00c8af",
  210. opacity: 0.4,
  211. transparent: !0,
  212. polygonOffset: true,
  213. //是否开启多边形偏移 //ie不开启时blank也不会闪烁
  214. polygonOffsetFactor: -0.9,
  215. //多边形偏移因子
  216. polygonOffsetUnits: -4.0,
  217. //多边形偏移单位
  218. }))
  219. if (texType == 'video') {
  220. } else {
  221. }
  222. }
  223. }
  224. this.texType = texType
  225. if (media == 'clear') {
  226. this.material_.opacity = 0.4
  227. this.texMedia = null
  228. return
  229. }
  230. if (texType == 'video') {//视频不能共用一个,否则会一起播放暂停
  231. var video
  232. if (media) {
  233. video = media
  234. } else {
  235. if (!this.info.texSrc) return
  236. var video = $(`<video controls="controls" loop autoplay x5-playsinline="" webkit-playsinline="true" playsinline="true" controlslist="nodownload"></video>`)[0]
  237. video.src = manage.dealURL(this.info.texSrc)
  238. video.name = this.info.fileName
  239. }
  240. video.setAttribute("crossOrigin", 'Anonymous')//要在src设置好前解决跨域
  241. $(video).on('contextmenu', function () {
  242. return false
  243. })//禁止右键点击出
  244. this.texMedia = video
  245. video.oncanplaythrough = () => {
  246. if (this.texMedia == video) {
  247. this.material_.map.needsUpdate = !0
  248. video.play()
  249. }
  250. }
  251. video.volume = 0
  252. video.muted = true
  253. video.currentTime = 0
  254. this.material_.map = new THREE.VideoTexture(video)
  255. this.material_.map.wrapS = this.material_.map.wrapT = THREE.ClampToEdgeWrapping
  256. this.material_.map.generateMipmaps = true
  257. } else if (texType == 'photo') {
  258. if (media) {
  259. this.texMedia = media
  260. this.info.texSrc = media.src
  261. this.material_.map = new THREE.Texture() //texture也不能共用一个,因为有的会有动画,就不一样
  262. this.material_.map.image = media //image可以共用
  263. this.material_.map.needsUpdate = !0
  264. } else {
  265. if (!this.info.texSrc) return
  266. this._loadDones = []
  267. this.material_.opacity = 0.1
  268. }
  269. } else if (texType == 'shine') {
  270. if (media) {
  271. this.changeShineTex(media)
  272. } else {
  273. this.styleImg = /* this.styleImg || */[]
  274. if (this.info.styleImg) {
  275. this.styleImg = this.info.styleImg.map((src) => {
  276. return { src: /* manage.dealURL( */src } //如果要dealURL,在predeal里
  277. })
  278. }
  279. this.changeShineTex(this.styleImg)
  280. }
  281. this.info.texSrc = null
  282. }
  283. if (this.material_.map) {
  284. /* this.material_.map.minFilter = THREE.LinearFilter;
  285. this.material_.map.magFilter = THREE.LinearFilter; */
  286. dealMap(this.material_.map)
  287. this.material_.color.set("#FFFFFF")
  288. this.material_.opacity = 1
  289. this.material_.needsUpdate = true
  290. }
  291. }
  292. changeShineTex(styleImg) {
  293. styleImg = styleImg || this.styleImg
  294. var tex1, tex2
  295. if (styleImg.length) {
  296. tex1 = Texture.load(styleImg[0].src)
  297. tex2 = Texture.load(styleImg[1] && styleImg[1].src || styleImg[0].src)
  298. } else {
  299. tex1 = defaultTex1
  300. tex2 = defaultTex2
  301. }
  302. this.changeMaterial(getShineMat(tex1, tex2))
  303. this.styleImg = styleImg
  304. this.info.styleImg = styleImg.map(img => img.src)
  305. }
  306. changeMaterial(mat) {
  307. this.material_ = mat
  308. this.mesh && this.mesh.traverse((mesh) => {
  309. if (mesh.material && !(mesh instanceof THREE.Box3Helper)) {
  310. mesh.material = this.material_
  311. }
  312. })
  313. }
  314. /*
  315. actionType: "common"
  316. infoAttribute: {images: [], styleImg: [], model: [], video: [], bgName: "background", iframe: [], title: "11",…}
  317. bgName: "background"
  318. content: "111"
  319. iframe: []
  320. images: []
  321. model: []
  322. styleImg: []
  323. title: "11"
  324. video: []
  325. isSprite: 0
  326. link: "https://www.4dmodel.com/SuperTwo/hot_online1/index.html#/?m=EDwn769489868"
  327. linkType: "common"
  328. noAction: 0
  329. order: 4
  330. position: {x: -4.238, y: 1.32, z: -0.648}
  331. rotation: {x: 0, y: 0.018105110200249575, z: 0}
  332. transformAtPanos: {}
  333. IO4Kq7494332: {actionTy
  334. depth: 0.08
  335. file: "https://super.4dage.com/data/TEST/edit/20200805_172635119.mp4"
  336. hasBox: 1
  337. height: 0.7289
  338. media: ["video"]
  339. pos: [-5.562, 1.349, 1.994]
  340. qua: [0, 0.70672, 0, 0.70749]
  341. sid: "1596619585929"
  342. transformAtPanos: {,…} */
  343. preDeal(info, source) {// source:来源
  344. var convertValue = function (v, Type) {
  345. var value
  346. if (v instanceof Array) {
  347. v.forEach((v1) => { v1 = parseFloat(v1) })
  348. value = new Type().fromArray(v)
  349. } else {
  350. if (!(v instanceof Type)) {
  351. for (let i in v) { v[i] = parseFloat(v[i]) }
  352. value = new Type().copy(v)
  353. } else {
  354. value = v
  355. }
  356. }
  357. return value
  358. }
  359. if (!info.transformAtPanos) info.transformAtPanos = {}
  360. if (source == 'byHot') {
  361. var infoAttribute = info.infoAttribute || {}
  362. info.title = infoAttribute.title || info.title
  363. info.model = infoAttribute.model || info.model || [] //模型链接
  364. info.images = infoAttribute.images || info.images || []
  365. info.video = infoAttribute.video || info.video || []
  366. info.bgName = infoAttribute.bgName || info.bgName
  367. info.backgroundMusic = info.backgroundMusic || info.backgroundMusic
  368. info.iframe = infoAttribute.iframe || info.iframe || []
  369. info.styleImg = infoAttribute.styleImg || info.styleImg || []
  370. info.content = infoAttribute.content || info.content
  371. {
  372. let action = CloneObject(settings.hotClickEvent.shine)
  373. if (info.actionType == 'noAction' || info.noAction) {
  374. action.examine = false,
  375. action.openHot = false
  376. } else if (info.actionType == 'dontExam') {
  377. action.examine = false
  378. }
  379. info.actionType = action
  380. }
  381. if (info.quaternion) {
  382. info.rotation = new THREE.Euler().setFromVector3(convertValue(info.quaternion, THREE.Quaternion))
  383. } else {
  384. info.rotation = new THREE.Euler().setFromVector3(convertValue(info.rotation, THREE.Vector3)) //热点的旧数据很多是字符串
  385. }
  386. var s = Hot.getDefaulScale(info.hotIconScale)
  387. info.scale = new THREE.Vector3(s, s, 0.02)
  388. delete info.infoAttribute
  389. /* for (let i in this.transformAtPanos) {
  390. info.transformAtPanos[i].pos = new THREE.Vector3().fromArray(info.transformAtPanos[i].pos)
  391. info.transformAtPanos[i].qua && (info.transformAtPanos[i].qua = new THREE.Quaternion().fromArray(info.transformAtPanos[i].qua))
  392. } */
  393. info.texType = "shine"
  394. } else {
  395. if (source == 'byOverlay') {
  396. info.texType = info.media[0]
  397. //info.title = info.texType == 'video'?'视频':'图片'
  398. info.texSrc = info.file
  399. info.actionType = CloneObject(settings.hotClickEvent[info.texType])//给一个默认
  400. delete info.media
  401. info.rotation = new THREE.Euler().setFromQuaternion(convertValue(info.qua, THREE.Quaternion))
  402. info.position = info.pos
  403. delete info.pos
  404. delete info.qua
  405. let a = info.texSrc.split('/')
  406. info.fileName = a.pop()
  407. info.scale = new THREE.Vector3(
  408. info.width,
  409. info.height,
  410. info.depth
  411. )
  412. delete info.width; delete info.height; delete info.depth
  413. delete info.file
  414. } else {
  415. info.rotation = new THREE.Euler().fromArray(info.rotation)//.setFromVector3(info.rotation)
  416. }
  417. info.model = info.model || [] //模型链接
  418. info.images = info.images || []
  419. info.video = info.video || []
  420. info.iframe = info.iframe || []
  421. info.styleImg = info.styleImg || []
  422. }
  423. if (info.texSrc) {
  424. info.texSrc = manage.removeSrcPostMark(info.texSrc)
  425. }
  426. //whole:
  427. //为了兼容旧数据,尽量和hot的数据靠近,最后保存在hot里
  428. info.position = convertValue(info.position, THREE.Vector3)
  429. info.scale = convertValue(info.scale, THREE.Vector3)
  430. delete info.quaternion
  431. info.linkType = info.linkType || "common"
  432. for (let i in info.transformAtPanos) {
  433. info.transformAtPanos[i].pos = new THREE.Vector3().fromArray(info.transformAtPanos[i].pos)
  434. //info.transformAtPanos[i].qua = new THREE.Quaternion().fromArray(info.transformAtPanos[i].qua)
  435. }
  436. }
  437. addBox(state) {
  438. if (state == !!this.hasBox) {
  439. return
  440. }
  441. if (state) {
  442. var box = new THREE.Mesh(_boxGeometry, _boxMat)
  443. box.position.set(0, 0, 1 / 2)
  444. box.renderOrder = 3
  445. this.plane.position.set(0, 0, 1)
  446. this.add(box)
  447. this.box = box
  448. } else {
  449. this.plane.position.set(0, 0, 0)
  450. this.remove(this.box)
  451. this.box = null
  452. }
  453. this.hasBox = this.info.hasBox = state
  454. }
  455. /* getSizeByScale() {
  456. return {
  457. width: settings.defaultOverlaySize[0] * this.scale.x,
  458. height: settings.defaultOverlaySize[1] * this.scale.y
  459. }
  460. }
  461. getScaleBySize(width, height) {
  462. return {
  463. x: width / settings.defaultOverlaySize[0],
  464. y: height / settings.defaultOverlaySize[1],
  465. }
  466. }*/
  467. setVisiblePanos(visibleData) {
  468. if (visibleData) this.info.visiblePanos = visibleData
  469. else if (!this.info.visiblePanos) this.getVisiblePanos()
  470. }
  471. getVisiblePanos() {//在不同点还不一样
  472. var depth = this.hasBox ? this.scale.z : 0
  473. var width = this.scale.x, height = this.scale.y
  474. var cornerPoint
  475. if (this.plane) {
  476. cornerPoint = [
  477. new THREE.Vector3(0, 0, depth),
  478. new THREE.Vector3(-width / 2, height / 2, depth),
  479. new THREE.Vector3(width / 2, height / 2, depth),
  480. new THREE.Vector3(width / 2, -height / 2, depth),
  481. new THREE.Vector3(-width / 2, -height / 2, depth),
  482. ]
  483. } else {
  484. var bound = new THREE.Box3().copy(this.info.modelBound.bound)
  485. var center = bound.center()
  486. cornerPoint = [
  487. new THREE.Vector3(center.x, center.y, center.z),
  488. new THREE.Vector3(bound.min.x, bound.min.y, bound.min.z),
  489. new THREE.Vector3(bound.min.x, bound.min.y, bound.max.z),
  490. new THREE.Vector3(bound.min.x, bound.max.y, bound.min.z),
  491. new THREE.Vector3(bound.max.x, bound.min.y, bound.min.z),
  492. new THREE.Vector3(bound.max.x, bound.max.y, bound.min.z),
  493. new THREE.Vector3(bound.max.x, bound.min.y, bound.max.z),
  494. new THREE.Vector3(bound.min.x, bound.max.y, bound.max.z),
  495. new THREE.Vector3(bound.max.x, bound.max.y, bound.max.z),
  496. ]
  497. }
  498. var getPos = (position) => {//每个overlay位置对应5个坐标,plane中心和四个角的位置
  499. if (this.plane) {
  500. return cornerPoint.map(e => {
  501. return e.clone().applyEuler(this.info.rotation).add(position)
  502. })
  503. } else {
  504. var matrixWorld = new THREE.Matrix4().compose(position, this.quaternion, this.scale)
  505. matrixWorld.multiplyMatrices(matrixWorld, this.mesh.matrix)
  506. return cornerPoint.map(e => {
  507. return e.clone().applyMatrix4(matrixWorld)
  508. })
  509. }
  510. }
  511. this.info.visiblePanos = []
  512. var customPositions = getPos(this.info.position)
  513. var posAtPanos = {}
  514. for (let panoId in this.info.transformAtPanos) {
  515. if (panoId == 'outSide') continue
  516. posAtPanos[panoId] = getPos(this.info.transformAtPanos[panoId].pos)
  517. }
  518. let maxCount = browser.isMobile() ? 2000 : 5000
  519. let c = model.panos.list.length * model.colliders.length
  520. if (window.isEdit || c < maxCount) { //编辑页面保险起见还是全部算完后才可浏览,就能保证保存全部的visiblePano
  521. this.info.visiblePanos = common.getVisiblePano(customPositions, model.panos.list, {
  522. model: model.colliders, posAtPanos
  523. })
  524. } else {
  525. let start = 0
  526. let interval = setInterval(() => {
  527. let end = start + Hot.visiPanosCountSlice
  528. end = Math.min(end, model.panos.list.length)
  529. let i = start
  530. start = end
  531. let panos = model.panos.list.slice(i, end)
  532. this.info.visiblePanos = this.info.visiblePanos.concat(common.getVisiblePano(customPositions, panos, {
  533. model: model.colliders, posAtPanos
  534. }))
  535. if (end >= model.panos.list.length) {
  536. console.log(window.hotsi ? (++window.hotsi) : (window.hotsi = 1))
  537. clearInterval(interval)
  538. }
  539. }, Hot.visiEveryDurSlice)// visiEveryDurSlice 等在main中定义
  540. }
  541. }
  542. updateVisible(panos, visibility) {
  543. if (window.isEdit && editTool.hotpoint.editSpot == this) {
  544. return this.visible = true
  545. }
  546. this.visible = visibility != void 0 ? visibility : (!this.info.visiblePanos || !!panos.find(pano => this.info.visiblePanos.includes(pano.id)))
  547. if (this.texType == 'video') {
  548. //this.switchPlay(this.visible, this.visible ? null : 'stop' );//可见时不操作;不可见时停止
  549. this.update(player)
  550. }
  551. }
  552. getCornerPoint() {//获取在每个漫游点上的视觉边界点 可以打开boxHelper和addBall来观测是否准确
  553. if (this.cornerPoints[player.currentPano.id]) {
  554. return this.cornerPoints[player.currentPano.id]
  555. } else {
  556. var boundPoint, cornerPoint
  557. var center//中心点
  558. if (this.plane) {
  559. center = this.plane.getWorldPosition()
  560. boundPoint = [
  561. new THREE.Vector3(-0.5, 0.5, 0),
  562. new THREE.Vector3(0.5, 0.5, 0),
  563. new THREE.Vector3(0.5, -0.5, 0),
  564. new THREE.Vector3(-0.5, -0.5, 0),
  565. ]
  566. } else {
  567. var bound = new THREE.Box3().copy(this.info.modelBound.bound)
  568. boundPoint = [
  569. new THREE.Vector3(bound.min.x, bound.min.y, bound.min.z),
  570. new THREE.Vector3(bound.min.x, bound.min.y, bound.max.z),
  571. new THREE.Vector3(bound.min.x, bound.max.y, bound.min.z),
  572. new THREE.Vector3(bound.max.x, bound.min.y, bound.min.z),
  573. new THREE.Vector3(bound.max.x, bound.max.y, bound.min.z),
  574. new THREE.Vector3(bound.max.x, bound.min.y, bound.max.z),
  575. new THREE.Vector3(bound.min.x, bound.max.y, bound.max.z),
  576. new THREE.Vector3(bound.max.x, bound.max.y, bound.max.z),
  577. ]
  578. }
  579. var maxLon = -Infinity
  580. var minLon = +Infinity
  581. var maxLat = -Infinity
  582. var minLat = +Infinity
  583. var pos1 = player.currentPano.position.clone()
  584. center = this.position.clone() //模型bound的中心点已经位移到了hot中心点。 注意不能用getWorldPosition,得到的会是偏移的
  585. var dir = center.clone().sub(pos1).normalize()
  586. var centerDirInfo = {}
  587. player.cameraControls.controls.panorama.lookAt.call(centerDirInfo, null, dir)
  588. boundPoint.forEach(e => {//lon左右
  589. var point = e.applyMatrix4(this.mesh.matrixWorld)
  590. var dir = point.clone().sub(pos1).normalize()
  591. var dirInfo = {}
  592. player.cameraControls.controls.panorama.lookAt.call(dirInfo, null, dir)
  593. var diffLon = (dirInfo.lon - centerDirInfo.lon) % 360
  594. if (Math.abs(diffLon) > 180) {//因为有时需要根据符号判断是在中心的左边还是右边,所以限制在180内
  595. diffLon += (diffLon > 0 ? -360 : 360)
  596. }
  597. var diffLat = dirInfo.lat - centerDirInfo.lat
  598. maxLon = Math.max(diffLon, maxLon)
  599. minLon = Math.min(diffLon, minLon)
  600. maxLat = Math.max(diffLat, maxLat)
  601. minLat = Math.min(diffLat, minLat)
  602. })
  603. var diffLon = maxLon - minLon
  604. var diffLat = maxLat - minLat
  605. if (diffLat > 180) {//可能是到了反面。不好算,直接返回所有boundPoint
  606. cornerPoint = boundPoint
  607. } else {
  608. //读取lon lat的最大最小值,勾勒出一个没有倾斜的矩形 。它比boundPoint看起来范围更大些
  609. maxLon = maxLon + centerDirInfo.lon
  610. maxLat = maxLat + centerDirInfo.lat
  611. minLon = minLon + centerDirInfo.lon
  612. minLat = minLat + centerDirInfo.lat
  613. var dirs = [
  614. math.getDirByLonLat(maxLon, maxLat),
  615. math.getDirByLonLat(minLon, minLat),
  616. math.getDirByLonLat(maxLon, minLat),
  617. math.getDirByLonLat(minLon, maxLat),
  618. ]
  619. cornerPoint = dirs.map(e => {
  620. return e.clone().add(pos1)
  621. })
  622. cornerPoint = [center, ...cornerPoint] //最后增加一个中心点
  623. }
  624. /* if(this.objObject){
  625. cornerPoint = [pos2, ...cornerPoint]
  626. } */
  627. //addPoints(cornerPoint)
  628. this.cornerPoints[player.currentPano.id] = { cornerPoint, diffLon, diffLat }
  629. return this.cornerPoints[player.currentPano.id]
  630. }
  631. }
  632. inSight() {
  633. //return true
  634. if (window.isEdit) return true // 太容易move了
  635. if (player.mode == 'panorama') {
  636. if (!player.camera) return
  637. var cornerPointInfo = this.getCornerPoint()
  638. var cornerPoint
  639. if (cornerPointInfo.diffLon < 15 && cornerPointInfo.diffLat < 15) {//当很小的时候,只判断中心点即可
  640. cornerPoint = [cornerPointInfo.cornerPoint[0]]
  641. } else {
  642. cornerPoint = cornerPointInfo.cornerPoint
  643. }
  644. for (let i = 0, j = cornerPoint.length; i < j; i++) {//只要有一点可见就算看见
  645. var pos2d = math.getPos2d(cornerPoint[i], player.camera, $("#player")[0])
  646. if (pos2d.trueSide && pos2d.inSight) return true
  647. }
  648. } else {//飞出要判断模型阻挡,有点耗时就算了
  649. return true
  650. }
  651. }
  652. update(player) {
  653. if (player.mode == 'panorama') {//实时监测播放
  654. if (this.texType == "video") {
  655. if (this.visible && !this.pausedByUser && this.inSight()) {
  656. this.videoControl(true)
  657. } else {
  658. this.videoControl(false)
  659. }
  660. } else if (this.info.animateInfo) {
  661. if (this.visible && this.inSight()) {
  662. GifTexDeal.start(this.animation)
  663. } else {
  664. GifTexDeal.stop(this.animation)
  665. }
  666. }
  667. }
  668. if (this.info.isSprite) {
  669. this.quaternion.copy(player.camera.quaternion)
  670. }
  671. this.updateScale()
  672. }
  673. updateScale(e, t) {//自适应调节大小
  674. if (!DATA.autoAdjustHotScale || this.texType != 'shine') return
  675. //let renderSize = player.sceneRenderer.renderer.domElement
  676. let renderSize = player.sceneRenderer.renderer.getSize()
  677. var scale = convertTool.getScaleForConstantSize($.extend(autoSizeInfo, {
  678. camera: player.camera, resolution: { x: renderSize.width, y: renderSize.height },
  679. position: this.position.clone(),
  680. }))
  681. this.plane.scale.set(scale, scale, scale)
  682. }
  683. switchPlay(state) {//手动播放暂停
  684. this.pausedByUser = !state
  685. this.videoControl(state)
  686. }
  687. videoControl(state) {
  688. if (this.texType != "video" || !this.material_.map) return
  689. var video = this.material_.map.image
  690. if (!state || state == 'stop') {
  691. if (!video.paused) {
  692. video.pause()
  693. //console.log("pause " + this.sid)
  694. }
  695. if (state == 'stop') {
  696. video.currentTime = 0
  697. }
  698. } else if (state) {
  699. if (video.paused) {
  700. video.play()
  701. //console.log("play " + this.sid)
  702. }
  703. }
  704. }
  705. /* setDefaultHotScale = function(){//设置成默认热点大小
  706. var w = DATA.hotIconScale) * g_HotMeshSize.g_HotMeshWidth
  707. this.scale.set( w, w, this.scale.z)
  708. } */
  709. setTitleElem() {
  710. var root = $("#hot")
  711. var title = this.info.title
  712. if (title) {
  713. if (!this.titleElem) {
  714. var elem = $(`<div></div>`)
  715. root.append(elem)
  716. this.titleElem = elem
  717. }
  718. this.titleElem.text(title)
  719. } else {
  720. if (this.titleElem) {
  721. this.titleElem.remove()
  722. this.titleElem = null
  723. }
  724. }
  725. }
  726. showTitle() {
  727. if (!this.titleElem) return
  728. var pos = math.getPos2d(this.position, player.camera, $("#player")[0])
  729. if (pos.trueSide) {//inSight
  730. this.titleElem.css({ "left": `${pos.pos.x}px`, "top": `${pos.pos.y}px ` })
  731. this.titleElem.css("display", "block")
  732. } else {
  733. this.titleElem.css("display", "none")
  734. }
  735. }
  736. hideTitle() {
  737. if (!this.titleElem) return
  738. this.titleElem.css("display", "none")
  739. }
  740. closestPanoTowardTag(e, t) {
  741. var i = []
  742. , n = []
  743. , r = this.mesh.getWorldPosition()
  744. if (e === "panorama") {
  745. /* var o = t.position.clone().sub(r).normalize();
  746. n.push(function(t, i) {//scoreFunctions.direction 最好这个漫游点在currentPano到热点之间的路径上。但是这样的话可能就看不到热点正面,所以删掉
  747. return function(e) {
  748. return e.position.clone().sub(t).normalize().dot(i) * window._settings.navigation.directionFactor
  749. }}(r, o)
  750. ) */
  751. }
  752. var a = new THREE.Vector3
  753. i.push(function (e) {
  754. return Math.abs(e.position.x - r.x) > window._settings.tags.visibility.cameraClearance || Math.abs(e.position.z - r.z) > window._settings.tags.visibility.cameraClearance
  755. },
  756. function (e) {
  757. a.copy(r).sub(e.position)
  758. var t = -THREE.Math.radToDeg(Math.atan(a.y / Math.sqrt(a.x * a.x + a.z * a.z)))
  759. , i = window._settings.tags.navigate.tiltTolerance
  760. return window._settings.insideLookLimitDown - i < t && t < window._settings.insideLookLimitUp + i
  761. },
  762. (pano) => { // add
  763. return player.checkHasNeighbor(pano)
  764. },
  765. (pano) => { // add
  766. // if (this.info && this.info.visiblePanos)
  767. return this.info.visiblePanos.includes(pano.id)
  768. }
  769. )
  770. n.push(
  771. (function (hot, i) { //scoreFunctions.distanceSquared
  772. return function (pano) {
  773. //i = a.navigation.distanceFactor
  774. return hot ? hot.position.distanceToSquared(pano.position) * i : 0
  775. }
  776. })(this, -2)
  777. ,
  778. (pano) => {//尽量正对hot
  779. let dir = new THREE.Vector3(0, 0, 1).applyQuaternion(this.quaternion)
  780. let dir2 = new THREE.Vector3().subVectors(pano.position, this.position).normalize()
  781. let s = dir.dot(dir2) * 10
  782. //console.log(pano.id + ":" + s)
  783. return s
  784. }
  785. )
  786. var s = t.model.panos.sortByScore(i, n)
  787. console.log(s)
  788. return s && 0 < s.length && s[0].pano
  789. }
  790. examine(options = {}) {
  791. console.log('打开热点,关闭背景音乐')
  792. // 判断当前背景音乐是开的还是关的
  793. let tempp = document.querySelector('#openMusic')
  794. if (tempp.style.display === 'block') {
  795. // 背景音乐当前为关闭状态
  796. window.musicFlagNow = '音乐关'
  797. } else {
  798. window.musicFlagNow = '音乐开'
  799. SoundManager.pause('bgm')
  800. }
  801. /**
  802. * 图片、视频之类的热点
  803. *
  804. * link: 提供默认效果的链接
  805. * linkType: 'common'
  806. * iframe: []
  807. */
  808. /**
  809. * 热点编辑里添加网页链接——普通
  810. *
  811. * link: 提供默认效果的链接
  812. * linkType: 'jumpLink'
  813. * iframe: ['http://47.112.166.173:8105/editPage/edit.html?m=1308']
  814. */
  815. /**
  816. * 热点编辑里添加网页链接——跳转
  817. *
  818. * link: 提供默认效果的链接
  819. * linkType: 'jumpLink'
  820. * iframe: ['http://47.112.166.173:8105/editPage/edit.html?m=1308']
  821. */
  822. /**
  823. * 热点编辑里添加网页链接——iframe
  824. * 提供默认效果的链接
  825. * linkType: 'iframeDiv'
  826. * iframe: ['...']
  827. */
  828. var openHot = this.info.link && this.info.actionType.openHot && !options.dontOpen
  829. var needExamine = options.examine || (!settings.dontExamHot && this.info.actionType.examine)
  830. if (!openHot && !needExamine) {
  831. return
  832. }
  833. if (openHot && this.info.linkType != "common" && this.info.iframe && this.info.iframe[0]) {
  834. if (false) { // 场景跳转(热点编辑里添加网页链接——跳转)
  835. // 注意,因为网站用了vue router, url里看上去像是查询片段的那一段其实是放在hash片段中的。
  836. const hotspotWebQuerySection = new URLSearchParams(this.info.iframe[0].split('?')[1])
  837. const targetSceneCode = hotspotWebQuerySection.get('m')
  838. const currentLocationQuerySection = new URLSearchParams(location.href.split('?')[1])
  839. const currentSceneCode = currentLocationQuerySection.get('m')
  840. if (currentSceneCode === '1300' && targetSceneCode === '1302') {
  841. const iframeElem = document.createElement('iframe')
  842. iframeElem.style.position = 'absolute'
  843. iframeElem.style.top = '50%'
  844. iframeElem.style.left = '50%'
  845. iframeElem.style.width = '600px'
  846. iframeElem.style.height = '800px'
  847. iframeElem.style.transform = 'translate(-50%, -50%)'
  848. iframeElem.style.zIndex = '9999'
  849. iframeElem.style.boxShadow = '0 0 0 1000px rgba(0, 0, 0, 0.85)'
  850. // iframeElem.src = 'http://192.168.20.16:8081/#/topic'
  851. iframeElem.src = '../quiz/index.html#/topic'
  852. document.documentElement.appendChild(iframeElem)
  853. const onMsg = (msg) => {
  854. console.log('message received!', msg)
  855. window.removeEventListener('message', onMsg, false)
  856. if (msg.data === 'quiz over') {
  857. // 跳转到新场景
  858. currentLocationQuerySection.set('m', targetSceneCode)
  859. const newLocation = location.href.split('?')[0] + '?' + currentLocationQuerySection.toString()
  860. location.assign(newLocation)
  861. location.reload(true)
  862. }
  863. }
  864. window.addEventListener('message', onMsg, false)
  865. } else {
  866. // 跳转到新场景
  867. currentLocationQuerySection.set('m', targetSceneCode)
  868. const newLocation = location.href.split('?')[0] + '?' + currentLocationQuerySection.toString()
  869. location.assign(newLocation)
  870. location.reload(true)
  871. }
  872. } else {
  873. // 不是场景跳转
  874. var src = this.info.iframe[0]
  875. if (this.info.linkType == "jumpLink") { // 新页面打开链接
  876. var newPage = window.open(src, "_blank")
  877. newPage.focus()
  878. } else if (this.info.linkType == "iframeDiv") { // iframe里打开链接
  879. var div = document.createElement("div")
  880. div.style.position = 'fixed'
  881. div.style.width = div.style.height = "100%"
  882. div.style.left = div.style.top = '0'
  883. div.style["z-index"] = "999"
  884. var exit = document.createElement("div")
  885. exit.style["background-image"] = "url(images/vrOffImg.png)"
  886. exit.style.position = 'absolute'
  887. exit.style.width = exit.style.height = "50px"
  888. exit.style.left = '17px'; exit.style.top = "20px"
  889. exit.style.cursor = "pointer"
  890. exit.style["background-repeat"] = "no-repeat"
  891. exit.style["background-size"] = "25%"
  892. exit.style["background-position"] = "center center"
  893. exit.style["background-color"] = "rgba(0, 0, 0, 0.2)"
  894. exit.style["border-radius"] = "50%"
  895. exit.style["z-index"] = "3"
  896. exit.onclick = () => {
  897. $(div).remove()
  898. Hot.closePopup()
  899. }
  900. var myElement = document.createElement("iframe")
  901. myElement.style.position = 'absolute'
  902. myElement.style.width = myElement.style.height = "100%"
  903. myElement.style.left = myElement.style.top = '0'
  904. myElement.src = this.info.iframe[0]
  905. $("body").append(div)
  906. div.appendChild(exit)
  907. div.appendChild(myElement)
  908. SoundManager.play('hot')
  909. }
  910. }
  911. } else {
  912. // 图片、视频之类的热点
  913. if (!player.currentPano) return
  914. var popup = document.getElementById("popup")
  915. if (openHot) {
  916. g_currentHot = this,
  917. popup.style.display = "block",
  918. popup.classList.add("wait")
  919. var n = document.createElement("iframe")
  920. SoundManager.play('hot')
  921. var src = getCommonHotspotUrl(this.info.link)
  922. n.src = src
  923. n.id = "id1",
  924. n.allowTransparency = "true"
  925. var a = document.getElementById("id1")
  926. if (void 0 === a || null == a) {
  927. document.querySelector(".popup-content").appendChild(n)
  928. document.body.classList.add('hotspot-detail-open')
  929. var s = !1
  930. window.loaddingSuccess = function () {
  931. s = !0
  932. }
  933. ,
  934. setTimeout(function e() {
  935. if (s) {
  936. var t = document.querySelector("#id1").contentWindow.document
  937. t.querySelector("video") && (t.querySelector("video").play(),
  938. !t.querySelector("video").paused && t.querySelector(".playPause") && t.querySelector(".playPause").classList.add("fa-pause")),
  939. t.querySelector("audio") && t.querySelector("audio").play()
  940. } else
  941. setTimeout(e, 300)
  942. }, 800)
  943. }
  944. }
  945. var done = function () {
  946. player.flyingToTag = !1
  947. openHot && popup.classList.remove("wait")
  948. }.bind(this)
  949. if (!needExamine) {
  950. done()
  951. return
  952. }
  953. var c = this.closestPanoTowardTag(player.mode, player.currentPano) || player.currentPano
  954. , h = this.mesh.getWorldPosition()
  955. player.flyingToTag = !0
  956. if (player.mode === 'panorama') {
  957. var d = {
  958. pano: c,
  959. lookAtPoint: h,
  960. duration: options.duration,
  961. maxDistanceOverride: null,
  962. skipWarpingCheck: !1,
  963. aimDuration: options.aimDuration,
  964. }
  965. player.flyToPano(d, done)
  966. } else {
  967. var p = {
  968. pano: c
  969. }
  970. if (h) {
  971. var f = (new THREE.Matrix4).lookAt(c.position, h, new THREE.Vector3(0, 1, 0))
  972. p.quaternion = (new THREE.Quaternion).setFromRotationMatrix(f)
  973. }
  974. p.callback = done,
  975. p.duration = options.duration || 1500,
  976. p.mode = 'panorama',
  977. p.aimDuration = options.aimDuration
  978. player.flyToNewMode(p)
  979. }
  980. }
  981. }
  982. addModel(object) {
  983. if (this.objObject) {
  984. this.remove(this.objObject)
  985. }
  986. this.objObject = object
  987. /* object.traverse((mesh)=>{
  988. if(mesh.material && mesh.type == "hotSprite"){
  989. mesh.material = this.material_;
  990. }
  991. }) */
  992. object.name = this.info.objName
  993. object.src = this.info.objSrc
  994. this.info.hasBox = false
  995. this.addBox(false)
  996. this.remove(this.plane)
  997. this.plane = null
  998. this.setMesh(this.objObject)
  999. //this.adjustModelAuto()
  1000. if (this.info.modelBound) {//应该不会改变
  1001. var s = this.info.modelBound.scaleRatio
  1002. this.mesh.scale.set(s, s, s)
  1003. this.mesh.position.fromArray(this.info.modelBound.position)
  1004. this.mesh.modelBound = this.info.modelBound
  1005. }
  1006. this.material_.side = THREE.FrontSide
  1007. this.changeBoxHelperDisplay(false)
  1008. //this.mesh.boxHelper.visible = true
  1009. }
  1010. addPlane() {//换成plane
  1011. if (this.plane) return
  1012. this.plane = new THREE.Mesh(_planeGeometry, this.material_)
  1013. this.remove(this.objObject)
  1014. this.objObject = null
  1015. delete this.info.objSrc
  1016. delete this.info.objName
  1017. delete this.info.modelBound
  1018. this.setMesh(this.plane)
  1019. //this.material_.side = THREE.DoubleSide //双面的话飞出来会看到悬空的
  1020. }
  1021. setMesh(mesh) {
  1022. this.mesh = mesh
  1023. this.add(this.mesh)
  1024. this.mesh.renderOrder = 3
  1025. this.changeMaterial(this.material_) //re applyTo every mesh
  1026. this.mesh.traverse((mesh) => {
  1027. mesh.type = "hotSprite" //raycaster use
  1028. })
  1029. if (!this.mesh.boxHelper) {
  1030. var boxHelper = this.mesh.children.find(e => e instanceof THREE.Box3Helper)
  1031. if (boxHelper) {
  1032. this.mesh.boxHelper = boxHelper
  1033. } else {
  1034. var bound
  1035. if (this.objObject) {
  1036. bound = new THREE.Box3().copy(this.info.modelBound.bound)
  1037. } else {
  1038. bound = planeBound
  1039. }
  1040. bound.expandByVector(new THREE.Vector3(0.0001, 0.0001, 0.0001))
  1041. this.mesh.boxHelper = new THREE.Box3Helper(bound, new THREE.Color("#00ffff"))
  1042. this.mesh.add(this.mesh.boxHelper)
  1043. this.mesh.boxHelper.material.depthTest = false
  1044. this.mesh.boxHelper.material.transparent = true
  1045. this.mesh.boxHelper.visible = false
  1046. }
  1047. }
  1048. }
  1049. changeBoxHelperDisplay(show) {
  1050. if (show) {
  1051. this.visible_ = this.visible
  1052. this.visible = true
  1053. this.mesh.boxHelper.visible = true
  1054. } else {
  1055. if (this.visible_ != void 0) {
  1056. this.visible = this.visible_
  1057. }
  1058. this.mesh.boxHelper.visible = false
  1059. }
  1060. }
  1061. /* addToLoadQueue() {
  1062. if (this.texType == 'photo') {
  1063. Hot.loadQueue.includes(this) || Hot.loadQueue.push(this)
  1064. }
  1065. } */
  1066. requestDownload(type, callback) {
  1067. var plane = this.plane
  1068. if (type == 'photo') {
  1069. if (this.photoHasRequestLoad || this.texType != 'photo') return
  1070. //console.log('overlay beginDownload : ' + this.sid)
  1071. /* this.material_.map = */Texture.load(this.info.texSrc, (tex) => {
  1072. callback && callback()
  1073. if (!tex.image) {
  1074. return //只是单纯用了相同src的tex,但image仍未加载完
  1075. }
  1076. if (!this._loadDones) return
  1077. dealMap(tex)
  1078. setTimeout(Hot.loadNext, 50)
  1079. hotGroup.children.forEach(e => {
  1080. if (e.info.texSrc == this.info.texSrc && e.info.texType == type) {
  1081. e.material_.color.set("#FFFFFF")
  1082. e.material_.opacity = 1
  1083. console.log('overlay loaded: ' + e.sid + " - " + this.info.texSrc.split('/').pop())
  1084. e.texMedia = tex.image
  1085. {//animation不同致使的不能使用同一个texture
  1086. if (window.isEdit) {
  1087. if (animateTexSrcs[e.info.texSrc]) {
  1088. e.material_.map = tex.clone() //编辑动画直接不用一个texture, 故而animation也不同
  1089. e.material_.map.needsUpdate = true
  1090. } else {
  1091. e.material_.map = tex
  1092. animateTexSrcs[e.info.texSrc] = 1
  1093. }
  1094. } else {
  1095. if (animateTexSrcs[e.info.texSrc]) {//已有该texSrc
  1096. let finded = false
  1097. for (let i of animateTexSrcs[e.info.texSrc]) {
  1098. if (ifSame(i[0], e.info.animateInfo)) {
  1099. e.material_.map = i[1]; finded = true; break
  1100. }
  1101. }
  1102. if (!finded) {
  1103. let tex_ = tex.clone()
  1104. animateTexSrcs[e.info.texSrc].set(e.info.animateInfo, tex_)
  1105. e.material_.map = tex_
  1106. }
  1107. } else {
  1108. let object = new Map()
  1109. object.set(e.info.animateInfo, tex)
  1110. animateTexSrcs[e.info.texSrc] = object//注册第一个texSrc
  1111. e.material_.map = tex
  1112. }
  1113. }
  1114. }
  1115. if (e.info.animateInfo && !e.animation) {
  1116. e.animation = GifTexDeal.addAnimation(e.material_.map, e, e.info.animateInfo, e.sid)
  1117. e.visible && e.inSight() && GifTexDeal.start(e.animation)
  1118. }
  1119. if (++photoLoaded == originPhotoCount) {//data2.js中的所有photo加载完毕
  1120. Hot.allPhotoLoaded = true
  1121. Hot.whenAllFileLoaded && Hot.allModelLoaded && Hot.whenAllFileLoaded()
  1122. }
  1123. {
  1124. e._loadDones.forEach(a => a())
  1125. e._loadDones = null
  1126. e.photoHasRequestLoad = true
  1127. }
  1128. e.material_.needsUpdate = true
  1129. }
  1130. })
  1131. })
  1132. this.photoHasRequestLoad = true
  1133. } else if (type == 'model') {
  1134. if (this.modelHasRequestLoad || !this.info.objSrc) return
  1135. //需要处理重复?
  1136. objLoader.load(this.info.objSrc, (object) => {
  1137. this.remove(this.mesh)
  1138. this.addModel(object)
  1139. callback && callback()
  1140. if (++modelLoaded == originModelCount) {//data2.js中的所有photo加载完毕
  1141. Hot.allModelLoaded = true
  1142. Hot.whenAllFileLoaded && Hot.allPhotoLoaded && Hot.whenAllFileLoaded()
  1143. }
  1144. })
  1145. this.modelHasRequestLoad = true
  1146. }
  1147. }
  1148. }
  1149. Hot.updateVisibles = function (panos) {
  1150. if (panos === true) {
  1151. model.hotGroup.children.forEach(e => e.updateVisible(null, true))
  1152. } else {
  1153. model.hotGroup.children.forEach(e => e.updateVisible(panos))
  1154. }
  1155. }
  1156. Hot.beginShineHot = function () {
  1157. if (!window.isEdit && shineMats.length == 0) return
  1158. transitions.trigger({
  1159. func: function (e) {
  1160. var opa = e <= .5 ? 2 * e : -2 * e + 2
  1161. shineMats.forEach(mat => {
  1162. mat.uniforms.opac.value = opa
  1163. })
  1164. },
  1165. cycling: !0,
  1166. duration: 3e3,
  1167. name: "hotShine"
  1168. })
  1169. }
  1170. Hot.getDefaulScale = function (hotIconScale) {
  1171. return (hotIconScale || DATA.hotIconScale) * g_HotMeshSize.g_HotMeshWidth
  1172. }
  1173. var loadings = []
  1174. Hot.loadQueue = [] //等待下载的overlay,目前只针对photo
  1175. Hot.maxLoadingCount = 3 //同时正在load图片的数量
  1176. Hot.loadNext = () => {//继续requestDownload loadQueue中前排的item
  1177. let count = Hot.maxLoadingCount - loadings.length
  1178. Hot.loadQueue.slice(0, count).forEach(e => {
  1179. loadings.push(e)
  1180. //console.log(e)
  1181. e.hot.requestDownload(e.type, () => {
  1182. var i = loadings.indexOf(e)
  1183. loadings.splice(i, 1)
  1184. })
  1185. })
  1186. Hot.loadQueue.splice(0, count)
  1187. }
  1188. Hot.getNeedLoad = function () {//计算获取loadQueue,每次都重新计算,覆盖旧的
  1189. if (!player || !player.domElement || !player.mode)
  1190. return
  1191. var hots1, hots2
  1192. if (player.mode != 'panorama') {
  1193. if (Hot.loadQueue.length == 0) {
  1194. hots1 = model.hotGroup.children.filter(e => e.texType == 'photo' && !e.photoHasRequestLoad)
  1195. hots2 = model.hotGroup.children.filter(e => e.info.objSrc && !e.modelHasRequestLoad)
  1196. Hot.loadQueue = hots1.map(e => { return { hot: e, type: "photo" } }).concat(
  1197. hots2.map(e => { return { hot: e, type: "model" } })
  1198. )
  1199. }
  1200. return
  1201. }
  1202. //Hot.loadWhenOutside = true
  1203. hots1 = model.hotGroup.children.filter(e => e.texType == 'photo' && !e.photoHasRequestLoad && (!e.info.visiblePanos || e.info.visiblePanos.includes(player.currentPano.id)))
  1204. hots2 = model.hotGroup.children.filter(e => e.info.objSrc && !e.modelHasRequestLoad && (!e.info.visiblePanos || e.info.visiblePanos.includes(player.currentPano.id)))
  1205. if (hots1.length + hots2.length == 0) {
  1206. hots1 = model.hotGroup.children.filter(e => e.texType == 'photo' && !e.photoHasRequestLoad)
  1207. hots2 = model.hotGroup.children.filter(e => e.info.objSrc && !e.modelHasRequestLoad)
  1208. }
  1209. var cameraDir = player.getDirection()
  1210. Hot.loadQueue = hots1.map(e => { return { hot: e, type: "photo" } }).concat(
  1211. hots2.map(e => { return { hot: e, type: "model" } })
  1212. )
  1213. var request = [(item) => {
  1214. return true
  1215. }]
  1216. var rank = [(item) => {
  1217. var dis = item.hot.mesh.getWorldPosition().distanceTo(player.position)
  1218. return -dis
  1219. }
  1220. , (item) => {
  1221. var tagDir = item.hot.mesh.getWorldPosition().sub(player.position)
  1222. var angle = tagDir.angleTo(cameraDir)
  1223. return -angle * 20
  1224. }]
  1225. var result = common.sortByScore(Hot.loadQueue, request, rank)
  1226. //Hot.loadQueue = result ? result.slice(0, 5).map(e=>e.item) : model.hotGroup.children.filter(e=>e.texType == 'photo' && !e.hasRequestLoad).slice(0, 2);
  1227. Hot.loadQueue = result ? result.slice(0, 5).map(e => e.item) : []
  1228. }
  1229. Hot.load = () => {//开始下载图片
  1230. Hot.getNeedLoad()
  1231. Hot.loadNext()
  1232. var hots1 = model.hotGroup.children.filter(e => e.texType == 'photo' && !e.photoHasRequestLoad)
  1233. var hots2 = model.hotGroup.children.filter(e => e.info.objSrc && !e.modelHasRequestLoad)
  1234. if (hots1.length + hots2.length > 0) {
  1235. setTimeout(Hot.load, 200)
  1236. } else {
  1237. Hot.allRequestLoad = true
  1238. console.log('allRequestLoad')
  1239. }
  1240. }
  1241. Hot.startLoad = () => {
  1242. originPhotoCount = hotGroup.children.filter(e => e.texType == 'photo').length
  1243. originModelCount = hotGroup.children.filter(e => !!e.info.objSrc).length
  1244. if (originPhotoCount == 0) Hot.allPhotoLoaded = true
  1245. if (originModelCount == 0) Hot.allModelLoaded = true
  1246. if (Hot.allModelLoaded && Hot.allPhotoLoaded) Hot.whenAllFileLoaded && Hot.whenAllFileLoaded()//所有加载完毕
  1247. else {
  1248. Hot.load()
  1249. }
  1250. }
  1251. window.Hot = Hot
  1252. /* var ball = new THREE.Mesh(new THREE.SphereBufferGeometry(0.01),new THREE.MeshBasicMaterial({color:"#f00",depthTest:false,transparent:true}))
  1253. var balls = []
  1254. var addPoint = function(point){
  1255. console.log(point)
  1256. var ball1 = ball.clone()
  1257. model.add(ball1);
  1258. ball1.position.copy(point)
  1259. balls.push(ball1)
  1260. }
  1261. var addPoints = function(points){
  1262. balls.forEach(e=>model.remove(e))
  1263. balls = []
  1264. points.forEach(e=>addPoint(e))
  1265. }
  1266. */
  1267. //判断是否是移动端,如果是给关闭按钮添加touchstart事件
  1268. Hot.closePopup = () => {// 关闭热点页面
  1269. if (!g_currentHot) return
  1270. console.log('关闭热点,打开背景音乐')
  1271. if (window.musicFlagNow === '音乐开') SoundManager.play('bgm')
  1272. g_currentHot = null
  1273. var hotPop = document.getElementById('popup')
  1274. hotPop.style.display = "none"
  1275. document.querySelector(".popup-content").removeChild(document.getElementById("id1"))
  1276. $("#popup iframe:last").remove()
  1277. document.body.classList.remove('hotspot-detail-open')
  1278. SoundManager.pause('hot', true)//自动播放被中断的音频 (bgm
  1279. return false
  1280. }
  1281. $('#closepop').on("click", () => {
  1282. Hot.closePopup()
  1283. })
  1284. Hot.createHotList = function () {
  1285. var docFragment = document.createDocumentFragment()
  1286. var hots = hotGroup.children.filter(hot => hot.info.actionType.openHot)
  1287. hots = hots.sort((a, b) => { return a.order - b.order })
  1288. window.myHotList = hots
  1289. hots.forEach((hot) => {
  1290. var li = document.createElement('li')
  1291. var span = document.createElement('span')
  1292. span.innerHTML = hot.info.title || '热点'
  1293. // console.log(span.innerHTML);
  1294. li.hot = hot // 列表每一项对应一个热点
  1295. li.appendChild(span)
  1296. docFragment.appendChild(li)
  1297. })
  1298. var ul = document.querySelector('#hotListContent ul')
  1299. ul && ul.appendChild(docFragment)
  1300. }
  1301. }
  1302. /*
  1303. 保存 JSON.stringify(editTool.hotpoint.getSavingInfo())
  1304. 可能需要再写一份保存到overlay 给旧场景项目使用
  1305. 最好后台有针对手机版的做一个压缩。压缩成几个档位。
  1306. 安卓手机firefox出现过视频mesh不可见或者闪烁的情况。
  1307. 视频最容易导致崩溃, 模型还好
  1308. 数据速率为4064kbps,1920*1080px 时测试部门电脑崩溃
  1309. 数据速率为1824kbps,720 *576px 时正常
  1310. 所以尽量降到2000以下 同时播放个数最好不超过2个 可能需要将src归零 并延迟加载、不自动播放
  1311. */