Hot.js 54 KB

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