vizicities/src/layer/tile/GeoJSONTileLayer.js

150 wiersze
3.9 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 extend from 'lodash.assign';
import GeoJSONTile from './GeoJSONTile';
import throttle from 'lodash.throttle';
import THREE from 'three';
// TODO: Offer on-the-fly slicing of static, non-tile-based GeoJSON files into a
// tile grid using geojson-vt
//
// See: https://github.com/mapbox/geojson-vt
// TODO: Make sure nothing is left behind in the heap after calling destroy()
// TODO: Consider pausing per-frame output during movement so there's little to
// no jank caused by previous tiles still processing
// This tile layer only updates the quadtree after world movement has occurred
//
// Tiles from previous quadtree updates are updated and outputted every frame
// (or at least every frame, throttled to some amount)
//
// This is because the complexity of TopoJSON tiles requires a lot of processing
// and so makes movement janky if updates occur every frame – only updating
// after movement means frame drops are less obvious due to heavy processing
// occurring while the view is generally stationary
//
// The downside is that until new tiles are requested and outputted you will
// see blank spaces as you orbit and move around
//
// An added benefit is that it dramatically reduces the number of tiles being
// requested over a period of time and the time it takes to go from request to
// screen output
//
// It may be possible to perform these updates per-frame once Web Worker
// processing is added
class GeoJSONTileLayer extends TileLayer {
constructor(path, options) {
var defaults = {
maxLOD: 14,
distance: 30000,
workers: false
};
options = extend({}, defaults, options);
super(options);
this.defaults = defaults;
this._path = path;
}
_onAdd(world) {
return new Promise((resolve, reject) => {
super._onAdd(world).then(() => {
// 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();
}, 0);
resolve(this);
}).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);
this._world.on('controlsMove', this._onControlsMove, this);
}
// Update and output tiles each frame (throttled)
_onWorldUpdate() {
if (this._pauseOutput || this._disableOutput) {
return;
}
this._outputTiles();
}
// Update tiles grid after world move, but don't output them
_onWorldMove(latlon, point) {
if (this._disableOutput) {
return;
}
this._pauseOutput = false;
this._calculateLOD();
}
// Pause updates during control movement for less visual jank
_onControlsMove() {
if (this._disableOutput) {
return;
}
this._pauseOutput = true;
}
_createTile(quadcode, layer) {
var newOptions = extend({}, this.defaults, this._options, {
outputToScene: false
});
delete newOptions.attribution;
return new GeoJSONTile(quadcode, this._path, layer, newOptions);
}
hide() {
this._pauseOutput = true;
super.hide();
}
show() {
this._pauseOutput = false;
super.show();
}
// 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;
// Run common destruction logic from parent
super.destroy();
}
}
export default GeoJSONTileLayer;
var noNew = function(path, options) {
return new GeoJSONTileLayer(path, options);
};
// Initialise without requiring new keyword
export {noNew as geoJSONTileLayer};