vizicities/src/layer/tile/ImageTileLayer.js

178 wiersze
6.1 KiB
JavaScript
Executable File
Czysty Wina Historia

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

import TileLayer from './TileLayer';
import ImageTile from './ImageTile';
import ImageTileLayerBaseMaterial from './ImageTileLayerBaseMaterial';
import throttle from 'lodash.throttle';
import THREE from 'three';
import extend from 'lodash.assign';
// TODO: Make sure nothing is left behind in the heap after calling destroy()
// DONE: Find a way to avoid the flashing caused by the gap between old tiles
// being removed and the new tiles being ready for display
//
// DONE: Simplest first step for MVP would be to give each tile mesh the colour
// of the basemap ground so it blends in a little more, or have a huge ground
// plane underneath all the tiles that shows through between tile updates.
//
// Could keep the old tiles around until the new ones are ready, though they'd
// probably need to be layered in a way so the old tiles don't overlap new ones,
// which is similar to how Leaflet approaches this (it has 2 layers)
//
// Could keep the tile from the previous quadtree level visible until all 4
// tiles at the new / current level have finished loading and are displayed.
// Perhaps by keeping a map of tiles by quadcode and a boolean for each of the
// child quadcodes showing whether they are loaded and in view. If all true then
// remove the parent tile, otherwise keep it on a lower layer.
// TODO: Load and display a base layer separate to the LOD grid that is at a low
// resolution – used as a backup / background to fill in empty areas / distance
// DONE: Fix the issue where some tiles just don't load, or at least the texture
// never shows up – tends to happen if you quickly zoom in / out past it while
// it's still loading, leaving a blank space
// TODO: Optimise the request of many image tiles – look at how Leaflet and
// OpenWebGlobe approach this (eg. batching, queues, etc)
// TODO: Cancel pending tile requests if they get removed from view before they
// reach a ready state (eg. cancel image requests, etc). Need to ensure that the
// images are re-requested when the tile is next in scene (even if from cache)
// TODO: Consider not performing an LOD calculation on every frame, instead only
// on move end so panning, orbiting and zooming stays smooth. Otherwise it's
// possible for performance to tank if you pan, orbit or zoom rapidly while all
// the LOD calculations are being made and new tiles requested.
//
// Pending tiles should continue to be requested and output to the scene on each
// frame, but no new LOD calculations should be made.
// This tile layer both updates the quadtree and outputs tiles on every frame
// (throttled to some amount)
//
// This is because the computational complexity of image tiles is generally low
// and so there isn't much jank when running these calculations and outputs in
// realtime
//
// The benefit to doing this is that the underlying map layer continues to
// refresh and update during movement, which is an arguably better experience
class ImageTileLayer extends TileLayer {
constructor(path, options) {
var defaults = {
distance: 300000
};
options = extend({}, defaults, options);
super(options);
this._path = path;
}
_onAdd(world) {
return new Promise((resolve, reject) => {
super._onAdd(world).then(() => {
// TODO: Removed because it causes depth buffer intersection issues
// with layer on top for some reason. Need to work out why and fix.
//
// Add base layer
// var geom = new THREE.PlaneBufferGeometry(2000000, 2000000, 1);
// var baseMaterial;
// if (this._world._environment._skybox) {
// baseMaterial = ImageTileLayerBaseMaterial('#f5f5f3', this._world._environment._skybox.getRenderTarget());
// } else {
// baseMaterial = ImageTileLayerBaseMaterial('#f5f5f3');
// }
// var mesh = new THREE.Mesh(geom, baseMaterial);
// // Setting this causes a depth-buffer intersection issue on the
// // all-the-things example
// // mesh.renderOrder = -1;
// mesh.rotation.x = -90 * Math.PI / 180;
// // TODO: It might be overkill to receive a shadow on the base layer as it's
// // rarely seen (good to have if performance difference is negligible)
// mesh.receiveShadow = true;
// this._baseLayer = mesh;
// this.add(mesh);
// Trigger initial quadtree calculation on the next frame
//
// TODO: This is a hack to ensure the camera is all set up - a better
// solution should be found
setTimeout(() => {
this._calculateLOD();
this._initEvents();
resolve(this);
}, 0);
}).catch(reject);
});
}
_initEvents() {
// Run LOD calculations based on render calls
//
// Throttled to 1 LOD calculation per 100ms
this._throttledWorldUpdate = throttle(this._onWorldUpdate, 100);
this._world.on('preUpdate', this._throttledWorldUpdate, this);
// this._world.on('move', this._onWorldMove, this);
}
_onWorldUpdate() {
this._calculateLOD();
this._outputTiles();
}
_onWorldMove(latlon, point) {
// this._moveBaseLayer(point);
}
_moveBaseLayer(point) {
this._baseLayer.position.x = point.x;
this._baseLayer.position.z = point.y;
}
_createTile(quadcode, layer) {
return new ImageTile(quadcode, this._path, layer);
}
// Destroys the layer and removes it from the scene and memory
destroy() {
this._world.off('preUpdate', this._throttledWorldUpdate);
this._world.off('move', this._onWorldMove);
this._throttledWorldUpdate = null;
// Dispose of mesh and materials
// this._baseLayer.geometry.dispose();
// this._baseLayer.geometry = null;
// if (this._baseLayer.material.map) {
// this._baseLayer.material.map.dispose();
// this._baseLayer.material.map = null;
// }
// this._baseLayer.material.dispose();
// this._baseLayer.material = null;
// this._baseLayer = null;
// Run common destruction logic from parent
super.destroy();
}
}
export default ImageTileLayer;
var noNew = function(path, options) {
return new ImageTileLayer(path, options);
};
// Initialise without requiring new keyword
export {noNew as imageTileLayer};