kopia lustrzana https://github.com/robhawkes/vizicities
Moved TopoJSON logic into GeoJSON components and added support for flat objects
rodzic
cf00340099
commit
a91ccae917
|
@ -76,7 +76,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
var _layerTileImageTileLayer2 = _interopRequireDefault(_layerTileImageTileLayer);
|
var _layerTileImageTileLayer2 = _interopRequireDefault(_layerTileImageTileLayer);
|
||||||
|
|
||||||
var _layerTileTopoJSONTileLayer = __webpack_require__(53);
|
var _layerTileGeoJSONTileLayer = __webpack_require__(53);
|
||||||
|
|
||||||
|
var _layerTileGeoJSONTileLayer2 = _interopRequireDefault(_layerTileGeoJSONTileLayer);
|
||||||
|
|
||||||
|
var _layerTileTopoJSONTileLayer = __webpack_require__(68);
|
||||||
|
|
||||||
var _layerTileTopoJSONTileLayer2 = _interopRequireDefault(_layerTileTopoJSONTileLayer);
|
var _layerTileTopoJSONTileLayer2 = _interopRequireDefault(_layerTileTopoJSONTileLayer);
|
||||||
|
|
||||||
|
@ -96,6 +100,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
Controls: _controlsIndex2['default'],
|
Controls: _controlsIndex2['default'],
|
||||||
EnvironmentLayer: _layerEnvironmentEnvironmentLayer2['default'],
|
EnvironmentLayer: _layerEnvironmentEnvironmentLayer2['default'],
|
||||||
ImageTileLayer: _layerTileImageTileLayer2['default'],
|
ImageTileLayer: _layerTileImageTileLayer2['default'],
|
||||||
|
GeoJSONTileLayer: _layerTileGeoJSONTileLayer2['default'],
|
||||||
TopoJSONTileLayer: _layerTileTopoJSONTileLayer2['default'],
|
TopoJSONTileLayer: _layerTileTopoJSONTileLayer2['default'],
|
||||||
Point: _geoPoint2['default'],
|
Point: _geoPoint2['default'],
|
||||||
LatLon: _geoLatLon2['default']
|
LatLon: _geoLatLon2['default']
|
||||||
|
@ -11203,9 +11208,9 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
|
var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
|
||||||
|
|
||||||
var _TopoJSONTile = __webpack_require__(54);
|
var _GeoJSONTile = __webpack_require__(54);
|
||||||
|
|
||||||
var _TopoJSONTile2 = _interopRequireDefault(_TopoJSONTile);
|
var _GeoJSONTile2 = _interopRequireDefault(_GeoJSONTile);
|
||||||
|
|
||||||
var _lodashThrottle = __webpack_require__(36);
|
var _lodashThrottle = __webpack_require__(36);
|
||||||
|
|
||||||
|
@ -11238,11 +11243,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
// It may be possible to perform these updates per-frame once Web Worker
|
// It may be possible to perform these updates per-frame once Web Worker
|
||||||
// processing is added
|
// processing is added
|
||||||
|
|
||||||
var TopoJSONTileLayer = (function (_TileLayer) {
|
var GeoJSONTileLayer = (function (_TileLayer) {
|
||||||
_inherits(TopoJSONTileLayer, _TileLayer);
|
_inherits(GeoJSONTileLayer, _TileLayer);
|
||||||
|
|
||||||
function TopoJSONTileLayer(path, options) {
|
function GeoJSONTileLayer(path, options) {
|
||||||
_classCallCheck(this, TopoJSONTileLayer);
|
_classCallCheck(this, GeoJSONTileLayer);
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
maxLOD: 14,
|
maxLOD: 14,
|
||||||
|
@ -11251,19 +11256,19 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
options = (0, _lodashAssign2['default'])(defaults, options);
|
options = (0, _lodashAssign2['default'])(defaults, options);
|
||||||
|
|
||||||
_get(Object.getPrototypeOf(TopoJSONTileLayer.prototype), 'constructor', this).call(this, options);
|
_get(Object.getPrototypeOf(GeoJSONTileLayer.prototype), 'constructor', this).call(this, options);
|
||||||
|
|
||||||
this._path = path;
|
this._path = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise without requiring new keyword
|
// Initialise without requiring new keyword
|
||||||
|
|
||||||
_createClass(TopoJSONTileLayer, [{
|
_createClass(GeoJSONTileLayer, [{
|
||||||
key: '_onAdd',
|
key: '_onAdd',
|
||||||
value: function _onAdd(world) {
|
value: function _onAdd(world) {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
_get(Object.getPrototypeOf(TopoJSONTileLayer.prototype), '_onAdd', this).call(this, world);
|
_get(Object.getPrototypeOf(GeoJSONTileLayer.prototype), '_onAdd', this).call(this, world);
|
||||||
|
|
||||||
// Trigger initial quadtree calculation on the next frame
|
// Trigger initial quadtree calculation on the next frame
|
||||||
//
|
//
|
||||||
|
@ -11325,7 +11330,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
options.style = this._options.style;
|
options.style = this._options.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0, _TopoJSONTile2['default'])(quadcode, this._path, layer, options);
|
if (this._options.topojson) {
|
||||||
|
options.topojson = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0, _GeoJSONTile2['default'])(quadcode, this._path, layer, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the layer and removes it from the scene and memory
|
// Destroys the layer and removes it from the scene and memory
|
||||||
|
@ -11338,15 +11347,15 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
this._throttledWorldUpdate = null;
|
this._throttledWorldUpdate = null;
|
||||||
|
|
||||||
// Run common destruction logic from parent
|
// Run common destruction logic from parent
|
||||||
_get(Object.getPrototypeOf(TopoJSONTileLayer.prototype), 'destroy', this).call(this);
|
_get(Object.getPrototypeOf(GeoJSONTileLayer.prototype), 'destroy', this).call(this);
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
return TopoJSONTileLayer;
|
return GeoJSONTileLayer;
|
||||||
})(_TileLayer3['default']);
|
})(_TileLayer3['default']);
|
||||||
|
|
||||||
exports['default'] = function (path, options) {
|
exports['default'] = function (path, options) {
|
||||||
return new TopoJSONTileLayer(path, options);
|
return new GeoJSONTileLayer(path, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
;
|
;
|
||||||
|
@ -11442,15 +11451,16 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
// Have a look at how this is done in Tangram before implementing anything as
|
// Have a look at how this is done in Tangram before implementing anything as
|
||||||
// the approach there is pretty similar and robust.
|
// the approach there is pretty similar and robust.
|
||||||
|
|
||||||
var TopoJSONTile = (function (_Tile) {
|
var GeoJSONTile = (function (_Tile) {
|
||||||
_inherits(TopoJSONTile, _Tile);
|
_inherits(GeoJSONTile, _Tile);
|
||||||
|
|
||||||
function TopoJSONTile(quadcode, path, layer, options) {
|
function GeoJSONTile(quadcode, path, layer, options) {
|
||||||
_classCallCheck(this, TopoJSONTile);
|
_classCallCheck(this, GeoJSONTile);
|
||||||
|
|
||||||
_get(Object.getPrototypeOf(TopoJSONTile.prototype), 'constructor', this).call(this, quadcode, path, layer);
|
_get(Object.getPrototypeOf(GeoJSONTile.prototype), 'constructor', this).call(this, quadcode, path, layer);
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
|
topojson: false,
|
||||||
filter: null,
|
filter: null,
|
||||||
style: {
|
style: {
|
||||||
color: '#ffffff'
|
color: '#ffffff'
|
||||||
|
@ -11464,7 +11474,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
// Request data for the tile
|
// Request data for the tile
|
||||||
|
|
||||||
_createClass(TopoJSONTile, [{
|
_createClass(GeoJSONTile, [{
|
||||||
key: 'requestTileAsync',
|
key: 'requestTileAsync',
|
||||||
value: function requestTileAsync() {
|
value: function requestTileAsync() {
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
@ -11487,7 +11497,7 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
// Clear request reference
|
// Clear request reference
|
||||||
this._request = null;
|
this._request = null;
|
||||||
|
|
||||||
_get(Object.getPrototypeOf(TopoJSONTile.prototype), 'destroy', this).call(this);
|
_get(Object.getPrototypeOf(GeoJSONTile.prototype), 'destroy', this).call(this);
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
key: '_createMesh',
|
key: '_createMesh',
|
||||||
|
@ -11654,7 +11664,13 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
console.time(this._tile);
|
console.time(this._tile);
|
||||||
|
|
||||||
var geojson = _topojson2['default'].feature(data, data.objects.vectile);
|
var geojson = data;
|
||||||
|
|
||||||
|
if (this._options.topojson) {
|
||||||
|
// TODO: Allow TopoJSON object to be customised so this isn't tied to
|
||||||
|
// Mapzen tiles
|
||||||
|
geojson = _topojson2['default'].feature(data, data.objects.vectile);
|
||||||
|
}
|
||||||
|
|
||||||
var offset = (0, _geoPoint2['default'])(0, 0);
|
var offset = (0, _geoPoint2['default'])(0, 0);
|
||||||
offset.x = -1 * this._center[0];
|
offset.x = -1 * this._center[0];
|
||||||
|
@ -11683,6 +11699,8 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
|
|
||||||
var style = this._options.style;
|
var style = this._options.style;
|
||||||
|
|
||||||
|
var allFlat = true;
|
||||||
|
|
||||||
features.forEach(function (feature) {
|
features.forEach(function (feature) {
|
||||||
// feature.geometry, feature.properties
|
// feature.geometry, feature.properties
|
||||||
|
|
||||||
|
@ -11759,26 +11777,32 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
_colours.push(_colour);
|
_colours.push(_colour);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up colours for every vertex with poor-mans AO on the sides
|
if (extruded.sides) {
|
||||||
extruded.sides.forEach(function (face, fi) {
|
if (allFlat) {
|
||||||
_colour = [];
|
allFlat = false;
|
||||||
|
}
|
||||||
|
|
||||||
// First face is always bottom-bottom-top
|
// Set up colours for every vertex with poor-mans AO on the sides
|
||||||
if (fi % 2 === 0) {
|
extruded.sides.forEach(function (face, fi) {
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
_colour = [];
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
// First face is always bottom-bottom-top
|
||||||
// Reverse winding for the second face
|
if (fi % 2 === 0) {
|
||||||
// top-top-bottom
|
|
||||||
} else {
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
}
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
// Reverse winding for the second face
|
||||||
|
// top-top-bottom
|
||||||
|
} else {
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
|
}
|
||||||
|
|
||||||
_faces.push(face);
|
_faces.push(face);
|
||||||
_colours.push(_colour);
|
_colours.push(_colour);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Skip bottom as there's no point rendering it
|
// Skip bottom as there's no point rendering it
|
||||||
// allFaces.push(extruded.faces);
|
// allFaces.push(extruded.faces);
|
||||||
|
@ -11980,8 +12004,10 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
mesh.castShadow = true;
|
mesh.castShadow = true;
|
||||||
mesh.receiveShadow = true;
|
mesh.receiveShadow = true;
|
||||||
|
|
||||||
// This is only useful for flat objects
|
if (allFlat) {
|
||||||
// mesh.renderOrder = 1;
|
// This is only useful for flat objects
|
||||||
|
mesh.renderOrder = 1;
|
||||||
|
}
|
||||||
|
|
||||||
this._mesh.add(mesh);
|
this._mesh.add(mesh);
|
||||||
|
|
||||||
|
@ -12037,11 +12063,11 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
return TopoJSONTile;
|
return GeoJSONTile;
|
||||||
})(_Tile3['default']);
|
})(_Tile3['default']);
|
||||||
|
|
||||||
exports['default'] = function (quadcode, path, layer, options) {
|
exports['default'] = function (quadcode, path, layer, options) {
|
||||||
return new TopoJSONTile(quadcode, path, layer, options);
|
return new GeoJSONTile(quadcode, path, layer, options);
|
||||||
};
|
};
|
||||||
|
|
||||||
;
|
;
|
||||||
|
@ -14896,6 +14922,39 @@ return /******/ (function(modules) { // webpackBootstrap
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***/ },
|
||||||
|
/* 68 */
|
||||||
|
/***/ function(module, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
Object.defineProperty(exports, '__esModule', {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
|
||||||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
|
||||||
|
|
||||||
|
var _GeoJSONTileLayer = __webpack_require__(53);
|
||||||
|
|
||||||
|
var _GeoJSONTileLayer2 = _interopRequireDefault(_GeoJSONTileLayer);
|
||||||
|
|
||||||
|
var _lodashAssign = __webpack_require__(3);
|
||||||
|
|
||||||
|
var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
|
||||||
|
|
||||||
|
// Initialise without requiring new keyword
|
||||||
|
|
||||||
|
exports['default'] = function (path, options) {
|
||||||
|
var defaults = {
|
||||||
|
topojson: true
|
||||||
|
};
|
||||||
|
|
||||||
|
options = (0, _lodashAssign2['default'])(defaults, options);
|
||||||
|
|
||||||
|
return (0, _GeoJSONTileLayer2['default'])(path, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
;
|
||||||
|
module.exports = exports['default'];
|
||||||
|
|
||||||
/***/ }
|
/***/ }
|
||||||
/******/ ])
|
/******/ ])
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -38,11 +38,12 @@ import Offset from 'polygon-offset';
|
||||||
// Have a look at how this is done in Tangram before implementing anything as
|
// Have a look at how this is done in Tangram before implementing anything as
|
||||||
// the approach there is pretty similar and robust.
|
// the approach there is pretty similar and robust.
|
||||||
|
|
||||||
class TopoJSONTile extends Tile {
|
class GeoJSONTile extends Tile {
|
||||||
constructor(quadcode, path, layer, options) {
|
constructor(quadcode, path, layer, options) {
|
||||||
super(quadcode, path, layer);
|
super(quadcode, path, layer);
|
||||||
|
|
||||||
var defaults = {
|
var defaults = {
|
||||||
|
topojson: false,
|
||||||
filter: null,
|
filter: null,
|
||||||
style: {
|
style: {
|
||||||
color: '#ffffff'
|
color: '#ffffff'
|
||||||
|
@ -226,7 +227,13 @@ class TopoJSONTile extends Tile {
|
||||||
_processTileData(data) {
|
_processTileData(data) {
|
||||||
console.time(this._tile);
|
console.time(this._tile);
|
||||||
|
|
||||||
var geojson = topojson.feature(data, data.objects.vectile);
|
var geojson = data;
|
||||||
|
|
||||||
|
if (this._options.topojson) {
|
||||||
|
// TODO: Allow TopoJSON object to be customised so this isn't tied to
|
||||||
|
// Mapzen tiles
|
||||||
|
geojson = topojson.feature(data, data.objects.vectile);
|
||||||
|
}
|
||||||
|
|
||||||
var offset = Point(0, 0);
|
var offset = Point(0, 0);
|
||||||
offset.x = -1 * this._center[0];
|
offset.x = -1 * this._center[0];
|
||||||
|
@ -255,6 +262,8 @@ class TopoJSONTile extends Tile {
|
||||||
|
|
||||||
var style = this._options.style;
|
var style = this._options.style;
|
||||||
|
|
||||||
|
var allFlat = true;
|
||||||
|
|
||||||
features.forEach(feature => {
|
features.forEach(feature => {
|
||||||
// feature.geometry, feature.properties
|
// feature.geometry, feature.properties
|
||||||
|
|
||||||
|
@ -331,26 +340,32 @@ class TopoJSONTile extends Tile {
|
||||||
_colours.push(_colour);
|
_colours.push(_colour);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Set up colours for every vertex with poor-mans AO on the sides
|
if (extruded.sides) {
|
||||||
extruded.sides.forEach((face, fi) => {
|
if (allFlat) {
|
||||||
_colour = [];
|
allFlat = false;
|
||||||
|
|
||||||
// First face is always bottom-bottom-top
|
|
||||||
if (fi % 2 === 0) {
|
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
|
||||||
// Reverse winding for the second face
|
|
||||||
// top-top-bottom
|
|
||||||
} else {
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
|
||||||
_colour.push([topColor.r, topColor.g, topColor.b]);
|
|
||||||
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_faces.push(face);
|
// Set up colours for every vertex with poor-mans AO on the sides
|
||||||
_colours.push(_colour);
|
extruded.sides.forEach((face, fi) => {
|
||||||
});
|
_colour = [];
|
||||||
|
|
||||||
|
// First face is always bottom-bottom-top
|
||||||
|
if (fi % 2 === 0) {
|
||||||
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
// Reverse winding for the second face
|
||||||
|
// top-top-bottom
|
||||||
|
} else {
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
_colour.push([topColor.r, topColor.g, topColor.b]);
|
||||||
|
_colour.push([bottomColor.r, bottomColor.g, bottomColor.b]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_faces.push(face);
|
||||||
|
_colours.push(_colour);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Skip bottom as there's no point rendering it
|
// Skip bottom as there's no point rendering it
|
||||||
// allFaces.push(extruded.faces);
|
// allFaces.push(extruded.faces);
|
||||||
|
@ -552,8 +567,10 @@ class TopoJSONTile extends Tile {
|
||||||
mesh.castShadow = true;
|
mesh.castShadow = true;
|
||||||
mesh.receiveShadow = true;
|
mesh.receiveShadow = true;
|
||||||
|
|
||||||
// This is only useful for flat objects
|
if (allFlat) {
|
||||||
// mesh.renderOrder = 1;
|
// This is only useful for flat objects
|
||||||
|
mesh.renderOrder = 1;
|
||||||
|
}
|
||||||
|
|
||||||
this._mesh.add(mesh);
|
this._mesh.add(mesh);
|
||||||
|
|
||||||
|
@ -608,5 +625,5 @@ class TopoJSONTile extends Tile {
|
||||||
|
|
||||||
// Initialise without requiring new keyword
|
// Initialise without requiring new keyword
|
||||||
export default function(quadcode, path, layer, options) {
|
export default function(quadcode, path, layer, options) {
|
||||||
return new TopoJSONTile(quadcode, path, layer, options);
|
return new GeoJSONTile(quadcode, path, layer, options);
|
||||||
};
|
};
|
|
@ -0,0 +1,121 @@
|
||||||
|
import TileLayer from './TileLayer';
|
||||||
|
import extend from 'lodash.assign';
|
||||||
|
import GeoJSONTile from './GeoJSONTile';
|
||||||
|
import throttle from 'lodash.throttle';
|
||||||
|
import THREE from 'three';
|
||||||
|
|
||||||
|
// 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: 2000
|
||||||
|
};
|
||||||
|
|
||||||
|
options = extend(defaults, options);
|
||||||
|
|
||||||
|
super(options);
|
||||||
|
|
||||||
|
this._path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
_onAdd(world) {
|
||||||
|
super._onAdd(world);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._outputTiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update tiles grid after world move, but don't output them
|
||||||
|
_onWorldMove(latlon, point) {
|
||||||
|
this._pauseOutput = false;
|
||||||
|
this._calculateLOD();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause updates during control movement for less visual jank
|
||||||
|
_onControlsMove() {
|
||||||
|
this._pauseOutput = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_createTile(quadcode, layer) {
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
if (this._options.filter) {
|
||||||
|
options.filter = this._options.filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._options.style) {
|
||||||
|
options.style = this._options.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._options.topojson) {
|
||||||
|
options.topojson = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GeoJSONTile(quadcode, this._path, layer, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise without requiring new keyword
|
||||||
|
export default function(path, options) {
|
||||||
|
return new GeoJSONTileLayer(path, options);
|
||||||
|
};
|
|
@ -1,117 +1,13 @@
|
||||||
import TileLayer from './TileLayer';
|
import GeoJSONTileLayer from './GeoJSONTileLayer';
|
||||||
import extend from 'lodash.assign';
|
import extend from 'lodash.assign';
|
||||||
import TopoJSONTile from './TopoJSONTile';
|
|
||||||
import throttle from 'lodash.throttle';
|
|
||||||
import THREE from 'three';
|
|
||||||
|
|
||||||
// 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 TopoJSONTileLayer extends TileLayer {
|
|
||||||
constructor(path, options) {
|
|
||||||
var defaults = {
|
|
||||||
maxLOD: 14,
|
|
||||||
distance: 2000
|
|
||||||
};
|
|
||||||
|
|
||||||
options = extend(defaults, options);
|
|
||||||
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this._path = path;
|
|
||||||
}
|
|
||||||
|
|
||||||
_onAdd(world) {
|
|
||||||
super._onAdd(world);
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
_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) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._outputTiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update tiles grid after world move, but don't output them
|
|
||||||
_onWorldMove(latlon, point) {
|
|
||||||
this._pauseOutput = false;
|
|
||||||
this._calculateLOD();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pause updates during control movement for less visual jank
|
|
||||||
_onControlsMove() {
|
|
||||||
this._pauseOutput = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_createTile(quadcode, layer) {
|
|
||||||
var options = {};
|
|
||||||
|
|
||||||
if (this._options.filter) {
|
|
||||||
options.filter = this._options.filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._options.style) {
|
|
||||||
options.style = this._options.style;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TopoJSONTile(quadcode, this._path, layer, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialise without requiring new keyword
|
// Initialise without requiring new keyword
|
||||||
export default function(path, options) {
|
export default function(path, options) {
|
||||||
return new TopoJSONTileLayer(path, options);
|
var defaults = {
|
||||||
|
topojson: true
|
||||||
|
};
|
||||||
|
|
||||||
|
options = extend(defaults, options);
|
||||||
|
|
||||||
|
return GeoJSONTileLayer(path, options);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import World from './World';
|
||||||
import Controls from './controls/index';
|
import Controls from './controls/index';
|
||||||
import EnvironmentLayer from './layer/environment/EnvironmentLayer';
|
import EnvironmentLayer from './layer/environment/EnvironmentLayer';
|
||||||
import ImageTileLayer from './layer/tile/ImageTileLayer';
|
import ImageTileLayer from './layer/tile/ImageTileLayer';
|
||||||
|
import GeoJSONTileLayer from './layer/tile/GeoJSONTileLayer';
|
||||||
import TopoJSONTileLayer from './layer/tile/TopoJSONTileLayer';
|
import TopoJSONTileLayer from './layer/tile/TopoJSONTileLayer';
|
||||||
import Point from './geo/Point';
|
import Point from './geo/Point';
|
||||||
import LatLon from './geo/LatLon';
|
import LatLon from './geo/LatLon';
|
||||||
|
@ -14,6 +15,7 @@ const VIZI = {
|
||||||
Controls: Controls,
|
Controls: Controls,
|
||||||
EnvironmentLayer: EnvironmentLayer,
|
EnvironmentLayer: EnvironmentLayer,
|
||||||
ImageTileLayer: ImageTileLayer,
|
ImageTileLayer: ImageTileLayer,
|
||||||
|
GeoJSONTileLayer: GeoJSONTileLayer,
|
||||||
TopoJSONTileLayer: TopoJSONTileLayer,
|
TopoJSONTileLayer: TopoJSONTileLayer,
|
||||||
Point: Point,
|
Point: Point,
|
||||||
LatLon: LatLon
|
LatLon: LatLon
|
||||||
|
|
Ładowanie…
Reference in New Issue