main2.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  1. import { scene, camera, light3, controls, renderer } from './common/scene2';
  2. import { setEvents } from './common/setEvents';
  3. import { convertToXYZ, getEventCenter, geodecoder } from './common/geoHelpers';
  4. import { mapTexture } from './common/mapTexture';
  5. import { getTween, memoize } from './common/utils';
  6. import topojson from 'topojson';
  7. import THREE from 'THREE';
  8. import d3 from 'd3';
  9. import fdage from 'fdage';
  10. var root,rotate;
  11. var getIndex = function(elem,index){
  12. index = index || 'index';
  13. return elem.getAttributeNode(index)&&elem.getAttributeNode(index).nodeValue;
  14. }
  15. var setIndex = function(elem,name,index){
  16. index = index || 'index';
  17. elem.setAttribute(index,name);
  18. }
  19. var getByIndex = function(elem,name,index){
  20. var result;
  21. for(var i=0; i<elem.children.length; i++){
  22. if(getIndex(elem.children[i],index)===name){
  23. result = elem.children[i];
  24. }
  25. }
  26. if(result) return result;
  27. else for(var i=0; i<elem.children.length; i++){
  28. result = result || getByIndex(elem.children[i],name,index);
  29. }
  30. return result;
  31. }
  32. var body = d3.select('body').node();
  33. var hint = d3.select("#hint").node()
  34. d3.json('data/world2.json', function (err, data) {
  35. d3.select("#loading").transition().duration(500)
  36. .style("opacity", 0).remove();
  37. var currentCountry,currentChosed,currentChName, overlay, chosedOverlay;
  38. var pointDown = 0;//鼠标按下为true,抬起为false
  39. var draged = 0; //是否才拖拽过
  40. var segments = 155; // number of vertices. Higher = better mouse accuracy
  41. var isMobile = /Android|iPhone|iPod|iPad|Windows Phone|IEMobile|BlackBerry|webOS/.test(navigator.userAgent);
  42. var regionObj;
  43. // Setup cache for country textures
  44. var countries = topojson.feature(data, data.objects.countries);
  45. var geo = geodecoder(countries.features);
  46. var textureCache = memoize(function (cntryID, color, lineWidth, lineColor) {
  47. var country = geo.find(cntryID);
  48. if(cntryID == "India"){
  49. /* for(var i=8; i<17; i++){
  50. country.geometry.coordinates[0][i][1] -=2;
  51. } */
  52. country.geometry.coordinates[0][8] = [92, 26.4]//92.07921,27.447946
  53. country.geometry.coordinates[0][9] = [92.27524,26.6]//[91.683,27.76053]
  54. country.geometry.coordinates[0][10] = [92.47524,26.6]//[92.47524,27.8821024]
  55. country.geometry.coordinates[0][11] = [93.41134113,26.628851]//[93.41134113,28.628851]
  56. country.geometry.coordinates[0][12] = [94.5634563,27.27140242]//[94.5634563,29.27140242]
  57. country.geometry.coordinates[0][13] = [95.39153,27.0282749]//[95.39153,29.0282749]
  58. country.geometry.coordinates[0][14] = [96.111611,27.445064]//[96.111611,29.445064]
  59. country.geometry.coordinates[0][15] = [96.579657,27.4]//[96.579657,28.819879933]
  60. country.geometry.coordinates[0][16] = [96.21962,27.903089]//[96.21962,28.403089]
  61. country.geometry.coordinates[0][17] = [96.3,27]
  62. }
  63. return mapTexture(country, color, lineWidth, lineColor);
  64. });
  65. window.mapTexture = mapTexture;
  66. // Base globe with blue "water"
  67. /* let blueMaterial = new THREE.MeshPhongMaterial({color: '#0889d5', transparent: true}); //2B3B59
  68. let sphere = new THREE.SphereGeometry(400, segments, segments);
  69. let baseGlobe = new THREE.Mesh(sphere, blueMaterial);
  70. baseGlobe.rotation.y = Math.PI;
  71. baseGlobe.addEventListener('click', onGlobeClick);
  72. baseGlobe.addEventListener('mousemove', onGlobeMousemove); */
  73. //baseGlobe.addEventListener('mousemove', onGlobeMousemove);
  74. var texture2DLoader = new THREE.TextureLoader();
  75. var earthMap, alphaGrayMap;
  76. earthMap=texture2DLoader.load("data/newEarth4.jpg");//newEarth.png
  77. let mapMat0 = new THREE.MeshPhongMaterial({map: earthMap, lights: true, transparent: true});
  78. mapMat0.specular = new THREE.Color(1,0.96,0.9);
  79. mapMat0.shininess = 1 ;
  80. //mapMat0.reflectivity = 10;
  81. var outerLayer = new THREE.Mesh(new THREE.SphereGeometry(400, segments, segments), mapMat0);
  82. outerLayer.rotation.y = Math.PI;
  83. //add base map layer with all countries
  84. /* let worldTexture = mapTexture(countries, '#647089');
  85. let mapMaterial = new THREE.MeshPhongMaterial({map: worldTexture,transparent: true});
  86. var baseMap = new THREE.Mesh(new THREE.SphereGeometry(401, segments, segments), mapMaterial);
  87. baseMap.rotation.y = Math.PI;
  88. mapMaterial.shininess = 1; */
  89. // create a container node and add the two meshes
  90. root = new THREE.Object3D();
  91. root.scale.set(1.5, 1.5, 1.5);
  92. //root.add(baseGlobe);
  93. //root.add(baseMap);
  94. root.add(outerLayer);
  95. scene.add(root);
  96. var bind = function(elem, event, func, bool) {
  97. bool = bool || false;
  98. if (elem.addEventListener)
  99. elem.addEventListener(event, func, bool);
  100. else if (elem.attachEvent)
  101. elem.attachEvent('on' + event, func);
  102. }
  103. var unbind = function(elem, event, func, bool) {
  104. bool = bool || false;
  105. if (elem.removeEventListener)
  106. elem.removeEventListener(event, func, bool);
  107. else if (elem.detachEvent)
  108. elem.detachEvent('on' + event, func);
  109. }
  110. var canvas = d3.select("#canvas").node();
  111. //地球滑动绑定:
  112. window.lastMouse = {};
  113. bind(canvas,"mousedown",function(event){
  114. window.lastMouse.x = event.offsetX;
  115. window.lastMouse.y = event.offsetY;
  116. })
  117. //地球初始转动绑定:
  118. rotate = true;
  119. var endRotate = function(){
  120. rotate = false;
  121. unbind(canvas,"mousedown",endRotate);
  122. }
  123. bind(canvas,"mousedown",endRotate);
  124. setEvents(camera,canvas, [outerLayer], 'click');
  125. setEvents(camera,canvas, [outerLayer], 'mousemove', 10);
  126. function rePos(o) { //重新定位
  127. var introOverlay = introduce.parentElement;
  128. if(layer<2){
  129. var ratio = 320/365;//横高比
  130. var h = window.innerHeight;
  131. var w = h * ratio;
  132. camera.aspect = w/h;
  133. camera.updateProjectionMatrix();
  134. renderer.setSize(w, h);
  135. introOverlay.style.left = w + "px";
  136. }else{
  137. introOverlay.style.left = "";
  138. }
  139. /* if(layer == 2){//intro要往左边来点
  140. } */
  141. }
  142. var canvasToImg = function(canvas){
  143. var type = 'png';
  144. var imgData = canvas.toDataURL(type);
  145. return imgData;
  146. }
  147. /* var artifactDiv = d3.select("#introduce").select("#artifact").node();
  148. for(var i=0; i<10; i++){
  149. var item = document.createElement('div');
  150. addClass(item,"item");
  151. artifactDiv.appendChild(item);
  152. } */
  153. d3.json('data/worldInfo2.json', function (err, introData) {//和info跳转有关
  154. outerLayer.addEventListener('click', onGlobeClick);
  155. outerLayer.addEventListener('mousemove', onGlobeMousemove);
  156. //跳转绑定:
  157. var i = d3.select("#introduce");
  158. var introduce = i.node();
  159. var artifact = i.select("#artifact").node();
  160. var introTitle = i.select(".introTitle").node();
  161. var introText = i.select(".introText").node();
  162. var backBtn = i.select("#back").node();
  163. var introBanner = i.select("#introBanner").node();
  164. var music = i.select("#music").node();
  165. bind(backBtn,"click",function(){//从第二层返回地球层
  166. layer = 1;
  167. removeClass(introduce,"layer2");
  168. //removeClass(introduce,"false3d");
  169. showIntroWithBannerAnima({animate:true});
  170. artifact.style.display = "";
  171. canvas.style.display = "";
  172. backBtn.style.display = "none";
  173. music.innerHTML = "";
  174. music.style.display = "none";
  175. regionObj = introData.region[currentChosed];
  176. introTitle.innerHTML = currentChName;
  177. introText.innerHTML = regionObj.regionIntro;
  178. rePos();
  179. var modelArea = d3.select("#modelArea").node();
  180. var imageArea = d3.select("#imageArea").node();
  181. if(modelArea){
  182. modelArea.style.display = "none";
  183. //if(isMobile){
  184. modelArea.children[0].src = "about:blank";//如果是手机就关闭释放内存
  185. modelArea.parentElement.removeChild(modelArea);
  186. modelArea = null;
  187. //}
  188. }
  189. if(imageArea){
  190. imageArea.style.display = "none";
  191. }
  192. })
  193. function showArtifactList(){
  194. var len = regionObj.artifact.length;
  195. for(var i=0; i<len; i++){
  196. var item = document.createElement('div');
  197. var inner = document.createElement('div');
  198. addClass(item,"item");
  199. artifact.appendChild(item);
  200. item.appendChild(inner);
  201. setIndex(item,i);
  202. bind(item,"click",clickItem)//绑定点击事件
  203. var itemObj = regionObj.artifact[i];
  204. //if(itemObj.type === "image"){
  205. item.children[0].style['background-image'] = "url(data/display/600/"+itemObj.name+".jpg)";
  206. //}
  207. }
  208. }
  209. function clickItem(){//点击列表
  210. layer = 2;
  211. hint.style.display = "none";
  212. addClass(introduce,"layer2");
  213. artifact.style.display = "none";
  214. backBtn.style.display = "block";
  215. canvas.style.display = "none";
  216. //getByIndex(menu,"artifactIntro").innerText = itemObj.introduce;
  217. rePos()
  218. showIntroWithBannerAnima({animate:true})
  219. var itemObj = regionObj.artifact[getIndex(this)];
  220. introTitle.innerHTML = itemObj.title || "";
  221. introText.innerHTML = itemObj.intro || "";
  222. if(itemObj.music){
  223. music.innerHTML += '<label>音频</label>';
  224. for(var i in itemObj.music){//elem.setAttribute('index',name); autoplay="autoplay"
  225. music.innerHTML += ('<audio loop="loop" controls="true"><source src="data/music/'+itemObj.music[i]+'" type="audio/mp3"></audio>');
  226. }
  227. music.style.display = "";
  228. }
  229. if(itemObj.type === "true3d" || itemObj.type === "false3d" ){
  230. //(itemObj.type === "false3d")&& addClass(introduce,"false3d");
  231. var modelArea = d3.select("#modelArea").node();
  232. if(!modelArea){
  233. modelArea = document.createElement("div");
  234. addClass(modelArea,"canvasArea");
  235. modelArea.id = "modelArea";
  236. body.appendChild(modelArea);
  237. }else{
  238. if(getIndex(modelArea)!==itemObj.name){//虽已有,但展示的是别的模型,要删除重新创建
  239. if(modelArea.children&&modelArea.children[0].src) modelArea.children[0].src = "about:blank";
  240. modelArea.parentElement.removeChild(modelArea);
  241. modelArea = document.createElement("div");
  242. addClass(modelArea,"canvasArea");
  243. modelArea.id = "modelArea";
  244. body.appendChild(modelArea);
  245. }
  246. modelArea.style.display = "";
  247. }
  248. if(getIndex(modelArea)!==itemObj.name){
  249. //fdage.embed( "data/ture3d/model/"+itemObj.name+".4dage", { root:modelArea, backgroundColor:[238/255,238/255,238/255],ifPlain:true, width: 800, height: 600, autoStart: true, fullFrame: true, pagePreset: false } );
  250. var page = document.createElement("iframe");
  251. page.src = "data/"+itemObj.type+"/"+itemObj.name+".html"+(itemObj.htmlTail?itemObj.htmlTail:"");
  252. modelArea.appendChild(page);
  253. setIndex(modelArea,itemObj.name);
  254. }
  255. }else{
  256. var imageArea = d3.select("#imageArea").node();
  257. if(!imageArea){
  258. imageArea = document.createElement("div");
  259. addClass(imageArea,"canvasArea");
  260. imageArea.id = "imageArea";
  261. body.appendChild(imageArea);
  262. var inner = document.createElement("div");
  263. imageArea.appendChild(inner);
  264. inner.style.width = "100%";
  265. inner.style.height = "94%";
  266. inner.style['margin-top'] = "2%";
  267. }else{
  268. var inner = imageArea.children[0];
  269. imageArea.style.display = "";
  270. }
  271. inner.style["background-image"] = "url(data/display/2048/"+itemObj.name+".jpg"+")";
  272. }
  273. }
  274. function showIntroWithBannerAnima(o){
  275. if(o.animateOrnot && introduce.style.display == "none"){//如果之前introduce消失,则要有动画,如果不小时,就无动画
  276. introduce.style.display = "";
  277. removeClass(introBanner,"show");
  278. setTimeout(function(){
  279. addClass(introBanner,"show");
  280. },100)
  281. }else if(o.show){
  282. introduce.style.display = "";
  283. }else if(o.hide){
  284. introduce.style.display = "none";
  285. removeClass(introBanner,"show");
  286. }
  287. if(o.animate){
  288. removeClass(introBanner,"show");
  289. setTimeout(function(){
  290. addClass(introBanner,"show");
  291. },100)
  292. }
  293. }
  294. function onGlobeMousemove(event,originEvent,_this) { //为什么mousedown的时候会立即触发mousemove?
  295. if(window.lastMouse.x){
  296. hint.style.display = "none"
  297. return;
  298. }
  299. var map, material;
  300. // Get pointc, convert to latitude/longitude
  301. var latlng = getEventCenter.call(this||_this, event, 400);
  302. // Look for country at that latitude/longitude
  303. var country = geo.search(latlng[0], latlng[1]);
  304. if(country && _this && country.code !== currentChosed){//点击的区域 _this表明是由click的触发的
  305. currentChosed = country.code;
  306. currentChName = country.chName;
  307. var imgName;
  308. switch(currentChosed){
  309. case "Germany":
  310. imgName = "Austria"; break; //共用一张
  311. case "Liang Yi":
  312. case "Yunnan Yi":
  313. imgName = "Yi"; break;
  314. case "England":
  315. case "United Kingdom":
  316. case "Belarus":
  317. imgName = "flower"; break;
  318. case "Indonesia":
  319. imgName = "Bali"; break;
  320. default:
  321. imgName = currentChosed;
  322. }
  323. introBanner.style["background-image"] = 'url("data/bannerImg/'+imgName+'.png")';
  324. //出现该地区的介绍和器物列表
  325. regionObj = introData.region[currentChosed];
  326. layer = 1;
  327. introTitle.innerHTML = currentChName;
  328. introText.innerHTML = "";
  329. artifact.innerHTML = "";
  330. if(regionObj){
  331. introText.innerHTML = regionObj.regionIntro;
  332. showArtifactList();
  333. }
  334. map = textureCache(country.code, 'rgba(180,36,1,1)');
  335. material = new THREE.MeshPhongMaterial({map: map,opacity:.5, transparent: true});
  336. material.shininess = 1 ;
  337. if (!chosedOverlay) {
  338. chosedOverlay = new THREE.Mesh(new THREE.SphereGeometry(405, 30, 30), material);
  339. chosedOverlay.rotation.y = Math.PI;
  340. root.add(chosedOverlay);
  341. }else{
  342. chosedOverlay.material = material;
  343. }
  344. }/* else if(country == null && _this){
  345. introduce.style.display = "none";
  346. BannerAnima(false);
  347. }else if(country&& _this){
  348. introduce.style.display = "";
  349. BannerAnima(true)
  350. } */
  351. if(!isMobile && country !== null){
  352. hint.style.display = "block";
  353. if(originEvent){
  354. hint.innerHTML = country.chName;
  355. hint.style.left = Math.min(originEvent.clientX + 10, window.innerWidth - hint.clientWidth)+ "px";
  356. hint.style.top = Math.min(originEvent.clientY + 10, window.innerHeight - hint.clientHeight)+ "px";
  357. }
  358. }
  359. if (!isMobile && country !== null && country.code !== currentCountry) { //滑动到的区域
  360. currentCountry = country.code;
  361. map = textureCache(country.code, 'rgba(255,255,255,0.4)', '2', '#FFFFFF');
  362. //map = isMobile ? mapTexture(geo.find(country.code), '#FFF900') : textureCache(country.code, '#FFF900');
  363. material = new THREE.MeshPhongMaterial({map: map,transparent: true});
  364. material.shininess = 1 ;
  365. if (!overlay) {
  366. overlay = new THREE.Mesh(new THREE.SphereGeometry(405, 30, 30), material);
  367. overlay.rotation.y = Math.PI;
  368. root.add(overlay);
  369. } else {
  370. overlay.material = material;
  371. }
  372. }else if(country == null){
  373. hint.style.display = "none";
  374. }
  375. if(country == null && _this){
  376. showIntroWithBannerAnima({hide:true})
  377. }else if(country&& _this){
  378. showIntroWithBannerAnima({show:true,animateOrnot:true})
  379. }
  380. }
  381. function onGlobeClick(event,originEvent) {//mouseup 在canvas上mouseup不一定会执行这个
  382. if(lastMouse.x){
  383. var x = originEvent.offsetX;
  384. var y = originEvent.offsetY;
  385. if((Math.abs(window.lastMouse.x - x)+Math.abs(window.lastMouse.y - y))>10){
  386. window.lastMouse.x = null;
  387. window.lastMouse.y = null;
  388. return;
  389. }
  390. }
  391. window.lastMouse.x = null;
  392. window.lastMouse.y = null;
  393. // Get pointc, convert to latitude/longitude
  394. var latlng = getEventCenter.call(this, event,400);//radius = 150
  395. latlng[1]+=(root.rotation.y*180/Math.PI -15); //因为一开始地球在旋转,所以要加上这个offset。另外地球左移后观察的中心点右移,所以也要改。
  396. // Get new camera position
  397. var temp = new THREE.Mesh();
  398. temp.position.copy(convertToXYZ(latlng, 1000));
  399. temp.lookAt(root.position);
  400. temp.rotateY(Math.PI);
  401. for (let key in temp.rotation) {
  402. if (temp.rotation[key] - camera.rotation[key] > Math.PI) {
  403. temp.rotation[key] -= Math.PI * 2;
  404. } else if (camera.rotation[key] - temp.rotation[key] > Math.PI) {
  405. temp.rotation[key] += Math.PI * 2;
  406. }
  407. }
  408. var tweenPos = getTween.call(camera, 'position', temp.position);
  409. d3.timer(tweenPos);
  410. var tweenRot = getTween.call(camera, 'rotation', temp.rotation);
  411. d3.timer(tweenRot);
  412. onGlobeMousemove(event,null,this);
  413. }
  414. });
  415. });
  416. function animate() {
  417. controls.update();
  418. light3.position.set(camera.position.x,camera.position.y,camera.position.z);
  419. light3.position.applyAxisAngle(new THREE.Vector3(0,1,0),0.9)
  420. if(root && rotate)root.rotation.y+=0.002;
  421. requestAnimationFrame(animate);
  422. renderer.render(scene, camera);
  423. }
  424. animate();
  425. window.cc = function(lon,lat){
  426. var scale = [0.03600360036003601,0.017366249624962495];
  427. var translate = [-180,-90];
  428. return [parseInt((lon-translate[0])/scale[0]), parseInt((lat-translate[1])/scale[1])];
  429. }
  430. window.vv = function(x,y){
  431. var scale = [0.03600360036003601,0.017366249624962495];
  432. var translate = [-180,-90];
  433. return [x*scale[0]+translate[0], y*scale[1]+translate[1]];
  434. }