three-render-objects.module.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. import { WebGLRenderer, Scene, PerspectiveCamera, Raycaster, TextureLoader, Vector2, Vector3, Box3, Color, Mesh, SphereGeometry, MeshBasicMaterial, BackSide, EventDispatcher, MOUSE, Quaternion, Spherical, Clock } from 'three';
  2. import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js';
  3. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
  4. import { FlyControls } from 'three/examples/jsm/controls/FlyControls.js';
  5. import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
  6. import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
  7. import { parseToRgb, opacify } from 'polished';
  8. import TWEEN from '@tweenjs/tween.js';
  9. import accessorFn from 'accessor-fn';
  10. import Kapsule from 'kapsule';
  11. function styleInject(css, ref) {
  12. if (ref === void 0) ref = {};
  13. var insertAt = ref.insertAt;
  14. if (!css || typeof document === 'undefined') {
  15. return;
  16. }
  17. var head = document.head || document.getElementsByTagName('head')[0];
  18. var style = document.createElement('style');
  19. style.type = 'text/css';
  20. if (insertAt === 'top') {
  21. if (head.firstChild) {
  22. head.insertBefore(style, head.firstChild);
  23. } else {
  24. head.appendChild(style);
  25. }
  26. } else {
  27. head.appendChild(style);
  28. }
  29. if (style.styleSheet) {
  30. style.styleSheet.cssText = css;
  31. } else {
  32. style.appendChild(document.createTextNode(css));
  33. }
  34. }
  35. var css_248z = ".scene-nav-info {\n bottom: 5px;\n width: 100%;\n text-align: center;\n color: slategrey;\n opacity: 0.7;\n font-size: 10px;\n}\n\n.scene-tooltip {\n color: lavender;\n font-size: 15px;\n}\n\n.scene-nav-info, .scene-tooltip {\n position: absolute;\n font-family: sans-serif;\n pointer-events: none;\n}\n\n.scene-container canvas:focus {\n outline: none;\n}";
  36. styleInject(css_248z);
  37. function _defineProperty(obj, key, value) {
  38. if (key in obj) {
  39. Object.defineProperty(obj, key, {
  40. value: value,
  41. enumerable: true,
  42. configurable: true,
  43. writable: true
  44. });
  45. } else {
  46. obj[key] = value;
  47. }
  48. return obj;
  49. }
  50. function _slicedToArray(arr, i) {
  51. return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
  52. }
  53. function _toConsumableArray(arr) {
  54. return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
  55. }
  56. function _arrayWithoutHoles(arr) {
  57. if (Array.isArray(arr)) return _arrayLikeToArray(arr);
  58. }
  59. function _arrayWithHoles(arr) {
  60. if (Array.isArray(arr)) return arr;
  61. }
  62. function _iterableToArray(iter) {
  63. if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
  64. }
  65. function _iterableToArrayLimit(arr, i) {
  66. var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
  67. if (_i == null) return;
  68. var _arr = [];
  69. var _n = true;
  70. var _d = false;
  71. var _s, _e;
  72. try {
  73. for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
  74. _arr.push(_s.value);
  75. if (i && _arr.length === i) break;
  76. }
  77. } catch (err) {
  78. _d = true;
  79. _e = err;
  80. } finally {
  81. try {
  82. if (!_n && _i["return"] != null) _i["return"]();
  83. } finally {
  84. if (_d) throw _e;
  85. }
  86. }
  87. return _arr;
  88. }
  89. function _unsupportedIterableToArray(o, minLen) {
  90. if (!o) return;
  91. if (typeof o === "string") return _arrayLikeToArray(o, minLen);
  92. var n = Object.prototype.toString.call(o).slice(8, -1);
  93. if (n === "Object" && o.constructor) n = o.constructor.name;
  94. if (n === "Map" || n === "Set") return Array.from(o);
  95. if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
  96. }
  97. function _arrayLikeToArray(arr, len) {
  98. if (len == null || len > arr.length) len = arr.length;
  99. for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
  100. return arr2;
  101. }
  102. function _nonIterableSpread() {
  103. throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  104. }
  105. function _nonIterableRest() {
  106. throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
  107. }
  108. var three = window.THREE ? window.THREE // Prefer consumption from global THREE, if exists
  109. : {
  110. WebGLRenderer: WebGLRenderer,
  111. Scene: Scene,
  112. PerspectiveCamera: PerspectiveCamera,
  113. Raycaster: Raycaster,
  114. TextureLoader: TextureLoader,
  115. Vector2: Vector2,
  116. Vector3: Vector3,
  117. Box3: Box3,
  118. Color: Color,
  119. Mesh: Mesh,
  120. SphereGeometry: SphereGeometry,
  121. MeshBasicMaterial: MeshBasicMaterial,
  122. BackSide: BackSide,
  123. EventDispatcher: EventDispatcher,
  124. MOUSE: MOUSE,
  125. Quaternion: Quaternion,
  126. Spherical: Spherical,
  127. Clock: Clock
  128. };
  129. var threeRenderObjects = Kapsule({
  130. props: {
  131. width: {
  132. "default": window.innerWidth,
  133. onChange: function onChange(width, state, prevWidth) {
  134. isNaN(width) && (state.width = prevWidth);
  135. }
  136. },
  137. height: {
  138. "default": window.innerHeight,
  139. onChange: function onChange(height, state, prevHeight) {
  140. isNaN(height) && (state.height = prevHeight);
  141. }
  142. },
  143. backgroundColor: {
  144. "default": '#000011'
  145. },
  146. backgroundImageUrl: {},
  147. onBackgroundImageLoaded: {},
  148. showNavInfo: {
  149. "default": true
  150. },
  151. skyRadius: {
  152. "default": 50000
  153. },
  154. objects: {
  155. "default": []
  156. },
  157. enablePointerInteraction: {
  158. "default": true,
  159. onChange: function onChange(_, state) {
  160. // Reset hover state
  161. state.hoverObj = null;
  162. if (state.toolTipElem) state.toolTipElem.innerHTML = '';
  163. },
  164. triggerUpdate: false
  165. },
  166. lineHoverPrecision: {
  167. "default": 1,
  168. triggerUpdate: false
  169. },
  170. hoverOrderComparator: {
  171. "default": function _default() {
  172. return -1;
  173. },
  174. triggerUpdate: false
  175. },
  176. // keep existing order by default
  177. hoverFilter: {
  178. "default": function _default() {
  179. return true;
  180. },
  181. triggerUpdate: false
  182. },
  183. // exclude objects from interaction
  184. tooltipContent: {
  185. triggerUpdate: false
  186. },
  187. hoverDuringDrag: {
  188. "default": false,
  189. triggerUpdate: false
  190. },
  191. clickAfterDrag: {
  192. "default": false,
  193. triggerUpdate: false
  194. },
  195. onHover: {
  196. "default": function _default() {},
  197. triggerUpdate: false
  198. },
  199. onClick: {
  200. "default": function _default() {},
  201. triggerUpdate: false
  202. },
  203. onRightClick: {
  204. triggerUpdate: false
  205. }
  206. },
  207. methods: {
  208. tick: function tick(state) {
  209. if (state.initialised) {
  210. state.controls.update && state.controls.update(state.clock.getDelta()); // timedelta is required for fly controls
  211. state.postProcessingComposer ? state.postProcessingComposer.render() // if using postprocessing, switch the output to it
  212. : state.renderer.render(state.scene, state.camera);
  213. state.extraRenderers.forEach(function (r) {
  214. return r.render(state.scene, state.camera);
  215. });
  216. if (state.enablePointerInteraction) {
  217. // Update tooltip and trigger onHover events
  218. var topObject = null;
  219. if (state.hoverDuringDrag || !state.isPointerDragging) {
  220. var intersects = this.intersectingObjects(state.pointerPos.x, state.pointerPos.y).filter(function (d) {
  221. return state.hoverFilter(d.object);
  222. }).sort(function (a, b) {
  223. return state.hoverOrderComparator(a.object, b.object);
  224. });
  225. var topIntersect = intersects.length ? intersects[0] : null;
  226. topObject = topIntersect ? topIntersect.object : null;
  227. state.intersectionPoint = topIntersect ? topIntersect.point : null;
  228. }
  229. if (topObject !== state.hoverObj) {
  230. state.onHover(topObject, state.hoverObj);
  231. state.toolTipElem.innerHTML = topObject ? accessorFn(state.tooltipContent)(topObject) || '' : '';
  232. state.hoverObj = topObject;
  233. }
  234. }
  235. TWEEN.update(); // update camera animation tweens
  236. }
  237. return this;
  238. },
  239. getPointerPos: function getPointerPos(state) {
  240. var _state$pointerPos = state.pointerPos,
  241. x = _state$pointerPos.x,
  242. y = _state$pointerPos.y;
  243. return {
  244. x: x,
  245. y: y
  246. };
  247. },
  248. cameraPosition: function cameraPosition(state, position, lookAt, transitionDuration) {
  249. var camera = state.camera; // Setter
  250. if (position && state.initialised) {
  251. var finalPos = position;
  252. var finalLookAt = lookAt || {
  253. x: 0,
  254. y: 0,
  255. z: 0
  256. };
  257. if (!transitionDuration) {
  258. // no animation
  259. setCameraPos(finalPos);
  260. setLookAt(finalLookAt);
  261. } else {
  262. var camPos = Object.assign({}, camera.position);
  263. var camLookAt = getLookAt();
  264. new TWEEN.Tween(camPos).to(finalPos, transitionDuration).easing(TWEEN.Easing.Quadratic.Out).onUpdate(setCameraPos).start(); // Face direction in 1/3rd of time
  265. new TWEEN.Tween(camLookAt).to(finalLookAt, transitionDuration / 3).easing(TWEEN.Easing.Quadratic.Out).onUpdate(setLookAt).start();
  266. }
  267. return this;
  268. } // Getter
  269. return Object.assign({}, camera.position, {
  270. lookAt: getLookAt()
  271. }); //
  272. function setCameraPos(pos) {
  273. var x = pos.x,
  274. y = pos.y,
  275. z = pos.z;
  276. if (x !== undefined) camera.position.x = x;
  277. if (y !== undefined) camera.position.y = y;
  278. if (z !== undefined) camera.position.z = z;
  279. }
  280. function setLookAt(lookAt) {
  281. state.controls.target = new three.Vector3(lookAt.x, lookAt.y, lookAt.z);
  282. }
  283. function getLookAt() {
  284. return Object.assign(new three.Vector3(0, 0, -1000).applyQuaternion(camera.quaternion).add(camera.position));
  285. }
  286. },
  287. zoomToFit: function zoomToFit(state) {
  288. var transitionDuration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  289. var padding = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
  290. for (var _len = arguments.length, bboxArgs = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) {
  291. bboxArgs[_key - 3] = arguments[_key];
  292. }
  293. return this.fitToBbox(this.getBbox.apply(this, bboxArgs), transitionDuration, padding);
  294. },
  295. fitToBbox: function fitToBbox(state, bbox) {
  296. var transitionDuration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
  297. var padding = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 10;
  298. // based on https://discourse.threejs.org/t/camera-zoom-to-fit-object/936/24
  299. var camera = state.camera;
  300. if (bbox) {
  301. var center = new three.Vector3(0, 0, 0); // reset camera aim to center
  302. var maxBoxSide = Math.max.apply(Math, _toConsumableArray(Object.entries(bbox).map(function (_ref) {
  303. var _ref2 = _slicedToArray(_ref, 2),
  304. coordType = _ref2[0],
  305. coords = _ref2[1];
  306. return Math.max.apply(Math, _toConsumableArray(coords.map(function (c) {
  307. return Math.abs(center[coordType] - c);
  308. })));
  309. }))) * 2; // find distance that fits whole bbox within padded fov
  310. var paddedFov = (1 - padding * 2 / state.height) * camera.fov;
  311. var fitHeightDistance = maxBoxSide / Math.atan(paddedFov * Math.PI / 180);
  312. var fitWidthDistance = fitHeightDistance / camera.aspect;
  313. var distance = Math.max(fitHeightDistance, fitWidthDistance);
  314. if (distance > 0) {
  315. var newCameraPosition = center.clone().sub(camera.position).normalize().multiplyScalar(-distance);
  316. this.cameraPosition(newCameraPosition, center, transitionDuration);
  317. }
  318. }
  319. return this;
  320. },
  321. getBbox: function getBbox(state) {
  322. var objFilter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : function () {
  323. return true;
  324. };
  325. var box = new three.Box3(new three.Vector3(0, 0, 0), new three.Vector3(0, 0, 0));
  326. var objs = state.objects.filter(objFilter);
  327. if (!objs.length) return null;
  328. objs.forEach(function (obj) {
  329. return box.expandByObject(obj);
  330. }); // extract global x,y,z min/max
  331. return Object.assign.apply(Object, _toConsumableArray(['x', 'y', 'z'].map(function (c) {
  332. return _defineProperty({}, c, [box.min[c], box.max[c]]);
  333. })));
  334. },
  335. getScreenCoords: function getScreenCoords(state, x, y, z) {
  336. var vec = new three.Vector3(x, y, z);
  337. vec.project(this.camera()); // project to the camera plane
  338. return {
  339. // align relative pos to canvas dimensions
  340. x: (vec.x + 1) * state.width / 2,
  341. y: -(vec.y - 1) * state.height / 2
  342. };
  343. },
  344. getSceneCoords: function getSceneCoords(state, screenX, screenY) {
  345. var distance = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
  346. var relCoords = new three.Vector2(screenX / state.width * 2 - 1, -(screenY / state.height) * 2 + 1);
  347. var raycaster = new three.Raycaster();
  348. raycaster.setFromCamera(relCoords, state.camera);
  349. return Object.assign({}, raycaster.ray.at(distance, new three.Vector3()));
  350. },
  351. intersectingObjects: function intersectingObjects(state, x, y) {
  352. var relCoords = new three.Vector2(x / state.width * 2 - 1, -(y / state.height) * 2 + 1);
  353. var raycaster = new three.Raycaster();
  354. raycaster.params.Line.threshold = state.lineHoverPrecision; // set linePrecision
  355. raycaster.setFromCamera(relCoords, state.camera);
  356. return raycaster.intersectObjects(state.objects, true);
  357. },
  358. renderer: function renderer(state) {
  359. return state.renderer;
  360. },
  361. scene: function scene(state) {
  362. return state.scene;
  363. },
  364. camera: function camera(state) {
  365. return state.camera;
  366. },
  367. postProcessingComposer: function postProcessingComposer(state) {
  368. return state.postProcessingComposer;
  369. },
  370. controls: function controls(state) {
  371. return state.controls;
  372. },
  373. tbControls: function tbControls(state) {
  374. return state.controls;
  375. } // to be deprecated
  376. },
  377. stateInit: function stateInit() {
  378. return {
  379. scene: new three.Scene(),
  380. camera: new three.PerspectiveCamera(),
  381. clock: new three.Clock()
  382. };
  383. },
  384. init: function init(domNode, state) {
  385. var _ref4 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
  386. _ref4$controlType = _ref4.controlType,
  387. controlType = _ref4$controlType === void 0 ? 'trackball' : _ref4$controlType,
  388. _ref4$rendererConfig = _ref4.rendererConfig,
  389. rendererConfig = _ref4$rendererConfig === void 0 ? {} : _ref4$rendererConfig,
  390. _ref4$extraRenderers = _ref4.extraRenderers,
  391. extraRenderers = _ref4$extraRenderers === void 0 ? [] : _ref4$extraRenderers,
  392. _ref4$waitForLoadComp = _ref4.waitForLoadComplete,
  393. waitForLoadComplete = _ref4$waitForLoadComp === void 0 ? true : _ref4$waitForLoadComp;
  394. // Wipe DOM
  395. domNode.innerHTML = ''; // Add relative container
  396. domNode.appendChild(state.container = document.createElement('div'));
  397. state.container.className = 'scene-container';
  398. state.container.style.position = 'relative'; // Add nav info section
  399. state.container.appendChild(state.navInfo = document.createElement('div'));
  400. state.navInfo.className = 'scene-nav-info';
  401. state.navInfo.textContent = {
  402. orbit: 'Left-click: rotate, Mouse-wheel/middle-click: zoom, Right-click: pan',
  403. trackball: 'Left-click: rotate, Mouse-wheel/middle-click: zoom, Right-click: pan',
  404. fly: 'WASD: move, R|F: up | down, Q|E: roll, up|down: pitch, left|right: yaw'
  405. }[controlType] || '';
  406. state.navInfo.style.display = state.showNavInfo ? null : 'none'; // Setup tooltip
  407. state.toolTipElem = document.createElement('div');
  408. state.toolTipElem.classList.add('scene-tooltip');
  409. state.container.appendChild(state.toolTipElem); // Capture pointer coords on move or touchstart
  410. state.pointerPos = new three.Vector2();
  411. state.pointerPos.x = -2; // Initialize off canvas
  412. state.pointerPos.y = -2;
  413. ['pointermove', 'pointerdown'].forEach(function (evType) {
  414. return state.container.addEventListener(evType, function (ev) {
  415. // track click state
  416. evType === 'pointerdown' && (state.isPointerPressed = true); // detect point drag
  417. !state.isPointerDragging && ev.type === 'pointermove' && (ev.pressure > 0 || state.isPointerPressed) // ev.pressure always 0 on Safari, so we used the isPointerPressed tracker
  418. && (ev.pointerType !== 'touch' || ev.movementX === undefined || [ev.movementX, ev.movementY].some(function (m) {
  419. return Math.abs(m) > 1;
  420. })) // relax drag trigger sensitivity on touch events
  421. && (state.isPointerDragging = true);
  422. if (state.enablePointerInteraction) {
  423. // update the pointer pos
  424. var offset = getOffset(state.container);
  425. state.pointerPos.x = ev.pageX - offset.left;
  426. state.pointerPos.y = ev.pageY - offset.top; // Move tooltip
  427. state.toolTipElem.style.top = "".concat(state.pointerPos.y, "px");
  428. state.toolTipElem.style.left = "".concat(state.pointerPos.x, "px");
  429. state.toolTipElem.style.transform = "translate(-".concat(state.pointerPos.x / state.width * 100, "%, 21px)"); // adjust horizontal position to not exceed canvas boundaries
  430. }
  431. function getOffset(el) {
  432. var rect = el.getBoundingClientRect(),
  433. scrollLeft = window.pageXOffset || document.documentElement.scrollLeft,
  434. scrollTop = window.pageYOffset || document.documentElement.scrollTop;
  435. return {
  436. top: rect.top + scrollTop,
  437. left: rect.left + scrollLeft
  438. };
  439. }
  440. }, {
  441. passive: true
  442. });
  443. }); // Handle click events on objs
  444. state.container.addEventListener('pointerup', function (ev) {
  445. state.isPointerPressed = false;
  446. if (state.isPointerDragging) {
  447. state.isPointerDragging = false;
  448. if (!state.clickAfterDrag) return; // don't trigger onClick after pointer drag (camera motion via controls)
  449. }
  450. requestAnimationFrame(function () {
  451. // trigger click events asynchronously, to allow hoverObj to be set (on frame)
  452. if (ev.button === 0) {
  453. // left-click
  454. state.onClick(state.hoverObj || null, ev, state.intersectionPoint); // trigger background clicks with null
  455. }
  456. if (ev.button === 2 && state.onRightClick) {
  457. // right-click
  458. state.onRightClick(state.hoverObj || null, ev, state.intersectionPoint);
  459. }
  460. });
  461. }, {
  462. passive: true,
  463. capture: true
  464. }); // use capture phase to prevent propagation blocking from controls (specifically for fly)
  465. state.container.addEventListener('contextmenu', function (ev) {
  466. if (state.onRightClick) ev.preventDefault(); // prevent default contextmenu behavior and allow pointerup to fire instead
  467. }); // Setup renderer, camera and controls
  468. state.renderer = new three.WebGLRenderer(Object.assign({
  469. antialias: true,
  470. alpha: true
  471. }, rendererConfig));
  472. state.renderer.setPixelRatio(Math.min(2, window.devicePixelRatio)); // clamp device pixel ratio
  473. state.container.appendChild(state.renderer.domElement); // Setup extra renderers
  474. state.extraRenderers = extraRenderers;
  475. state.extraRenderers.forEach(function (r) {
  476. // overlay them on top of main renderer
  477. r.domElement.style.position = 'absolute';
  478. r.domElement.style.top = '0px';
  479. r.domElement.style.pointerEvents = 'none';
  480. state.container.appendChild(r.domElement);
  481. }); // configure post-processing composer
  482. state.postProcessingComposer = new EffectComposer(state.renderer);
  483. state.postProcessingComposer.addPass(new RenderPass(state.scene, state.camera)); // render scene as first pass
  484. // configure controls
  485. state.controls = new {
  486. trackball: TrackballControls,
  487. orbit: OrbitControls,
  488. fly: FlyControls
  489. }[controlType](state.camera, state.renderer.domElement);
  490. if (controlType === 'fly') {
  491. state.controls.movementSpeed = 300;
  492. state.controls.rollSpeed = Math.PI / 6;
  493. state.controls.dragToLook = true;
  494. }
  495. if (controlType === 'trackball' || controlType === 'orbit') {
  496. state.controls.minDistance = 0.1;
  497. state.controls.maxDistance = state.skyRadius;
  498. state.controls.addEventListener('start', function () {
  499. state.controlsEngaged = true;
  500. });
  501. state.controls.addEventListener('change', function () {
  502. if (state.controlsEngaged) {
  503. state.controlsDragging = true;
  504. }
  505. });
  506. state.controls.addEventListener('end', function () {
  507. state.controlsEngaged = false;
  508. state.controlsDragging = false;
  509. });
  510. }
  511. [state.renderer, state.postProcessingComposer].concat(_toConsumableArray(state.extraRenderers)).forEach(function (r) {
  512. return r.setSize(state.width, state.height);
  513. });
  514. state.camera.aspect = state.width / state.height;
  515. state.camera.updateProjectionMatrix();
  516. state.camera.position.z = 1000; // add sky
  517. state.scene.add(state.skysphere = new three.Mesh());
  518. state.skysphere.visible = false;
  519. state.loadComplete = state.scene.visible = !waitForLoadComplete;
  520. window.scene = state.scene;
  521. },
  522. update: function update(state, changedProps) {
  523. // resize canvas
  524. if (state.width && state.height && (changedProps.hasOwnProperty('width') || changedProps.hasOwnProperty('height'))) {
  525. state.container.style.width = state.width;
  526. state.container.style.height = state.height;
  527. [state.renderer, state.postProcessingComposer].concat(_toConsumableArray(state.extraRenderers)).forEach(function (r) {
  528. return r.setSize(state.width, state.height);
  529. });
  530. state.camera.aspect = state.width / state.height;
  531. state.camera.updateProjectionMatrix();
  532. }
  533. if (changedProps.hasOwnProperty('skyRadius') && state.skyRadius) {
  534. state.controls.hasOwnProperty('maxDistance') && changedProps.skyRadius && (state.controls.maxDistance = state.skyRadius);
  535. state.camera.far = state.skyRadius * 2.5;
  536. state.camera.updateProjectionMatrix();
  537. state.skysphere.geometry = new three.SphereGeometry(state.skyRadius);
  538. }
  539. if (changedProps.hasOwnProperty('backgroundColor')) {
  540. var alpha = parseToRgb(state.backgroundColor).alpha;
  541. if (alpha === undefined) alpha = 1;
  542. state.renderer.setClearColor(new three.Color(opacify(1, state.backgroundColor)), alpha);
  543. }
  544. if (changedProps.hasOwnProperty('backgroundImageUrl')) {
  545. if (!state.backgroundImageUrl) {
  546. state.skysphere.visible = false;
  547. state.skysphere.material.map = null;
  548. !state.loadComplete && finishLoad();
  549. } else {
  550. new three.TextureLoader().load(state.backgroundImageUrl, function (texture) {
  551. state.skysphere.material = new three.MeshBasicMaterial({
  552. map: texture,
  553. side: three.BackSide
  554. });
  555. state.skysphere.visible = true; // triggered when background image finishes loading (asynchronously to allow 1 frame to load texture)
  556. state.onBackgroundImageLoaded && setTimeout(state.onBackgroundImageLoaded);
  557. !state.loadComplete && finishLoad();
  558. });
  559. }
  560. }
  561. changedProps.hasOwnProperty('showNavInfo') && (state.navInfo.style.display = state.showNavInfo ? null : 'none');
  562. if (changedProps.hasOwnProperty('objects')) {
  563. (changedProps.objects || []).forEach(function (obj) {
  564. return state.scene.remove(obj);
  565. }); // Clear the place
  566. state.objects.forEach(function (obj) {
  567. return state.scene.add(obj);
  568. }); // Add to scene
  569. } //
  570. function finishLoad() {
  571. state.loadComplete = state.scene.visible = true;
  572. }
  573. }
  574. });
  575. export default threeRenderObjects;