kopia lustrzana https://github.com/robhawkes/vizicities
Added pre-existing logic for worker-based tile layers
rodzic
1e8d26c71e
commit
89ea1ee87d
|
@ -0,0 +1,18 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>Web Workers Basic ViziCities Example</title>
|
||||
<link rel="stylesheet" href="main.css">
|
||||
<link rel="stylesheet" href="../../dist/vizicities.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="world"></div>
|
||||
|
||||
<script src="../vendor/three.min.js"></script>
|
||||
<script src="../vendor/TweenMax.min.js"></script>
|
||||
<script src="../../dist/vizicities.min.js"></script>
|
||||
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,4 @@
|
|||
* { margin: 0; padding: 0; }
|
||||
html, body { height: 100%; overflow: hidden;}
|
||||
|
||||
#world { height: 100%; }
|
|
@ -0,0 +1,47 @@
|
|||
// Manhattan
|
||||
var coords = [40.739940, -73.988801];
|
||||
|
||||
var world = VIZI.world('world', {
|
||||
skybox: false,
|
||||
postProcessing: false
|
||||
}).setView(coords);
|
||||
|
||||
// Add controls
|
||||
VIZI.Controls.orbit().addTo(world);
|
||||
|
||||
// Leave a single CPU for the main browser thread
|
||||
world.createWorkers(7).then(() => {
|
||||
console.log('Workers ready');
|
||||
|
||||
// CartoDB basemap
|
||||
VIZI.imageTileLayer('http://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}.png', {
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, © <a href="http://cartodb.com/attributions">CartoDB</a>'
|
||||
}).addTo(world).then(() => {
|
||||
console.log('Added image tile layer to world');
|
||||
});;
|
||||
|
||||
// Buildings from Mapzen
|
||||
VIZI.topoJSONWorkerTileLayer('https://vector.mapzen.com/osm/buildings/{z}/{x}/{y}.topojson?api_key=vector-tiles-NT5Emiw', {
|
||||
interactive: false,
|
||||
style: function(feature) {
|
||||
var height;
|
||||
|
||||
if (feature.properties.height) {
|
||||
height = feature.properties.height;
|
||||
} else {
|
||||
height = 10 + Math.random() * 10;
|
||||
}
|
||||
|
||||
return {
|
||||
height: height
|
||||
};
|
||||
},
|
||||
filter: function(feature) {
|
||||
// Don't show points
|
||||
return feature.geometry.type !== 'Point';
|
||||
},
|
||||
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://whosonfirst.mapzen.com#License">Who\'s On First</a>.'
|
||||
}).addTo(world).then(() => {
|
||||
console.log('Added TopoJSON layer to world');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,61 @@
|
|||
importScripts('../vendor/three.min.js');
|
||||
|
||||
// Special version of ViziCities without controls (no DOM errors)
|
||||
importScripts('../../dist/vizicities-worker.min.js');
|
||||
|
||||
const DEBUG = false;
|
||||
|
||||
if (DEBUG) { console.log('Worker started', performance.now()); }
|
||||
|
||||
// Send startup message to main thread
|
||||
postMessage({
|
||||
type: 'startup',
|
||||
payload: performance.now()
|
||||
});
|
||||
|
||||
// Recieve message from main thread
|
||||
onmessage = (event) => {
|
||||
if (!event.data.method) {
|
||||
postMessage({
|
||||
type: 'error',
|
||||
payload: 'No method provided'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var time = performance.now();
|
||||
if (DEBUG) { console.log('Message received from main thread', time, event.data); }
|
||||
// if (DEBUG) console.log('Time to receive message', time - event.data);
|
||||
|
||||
// Run method
|
||||
// if (!methods[event.data.method]) {
|
||||
// postMessage({
|
||||
// type: 'error',
|
||||
// payload: 'Method not found'
|
||||
// });
|
||||
|
||||
// return;
|
||||
// }
|
||||
|
||||
var methods = event.data.method.split('.');
|
||||
|
||||
var _method = VIZI[methods[0]];
|
||||
|
||||
if (methods.length > 1) {
|
||||
for (var i = 1; i < methods.length; i++) {
|
||||
_method = _method[methods[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Call method with given arguments
|
||||
_method.apply(this, event.data.args).then((result) => {
|
||||
console.log('Message sent from worker', performance.now());
|
||||
|
||||
// Return results
|
||||
postMessage({
|
||||
type: 'result',
|
||||
payload: result.data
|
||||
}, result.transferrables);
|
||||
});
|
||||
};
|
|
@ -17,6 +17,7 @@
|
|||
import Layer from '../Layer';
|
||||
import extend from 'lodash.assign';
|
||||
import THREE from 'three';
|
||||
import Geo from '../../geo/Geo';
|
||||
import {latLon as LatLon} from '../../geo/LatLon';
|
||||
import {point as Point} from '../../geo/Point';
|
||||
import earcut from 'earcut';
|
||||
|
|
|
@ -0,0 +1,341 @@
|
|||
import Tile from './Tile';
|
||||
import {geoJSONWorkerLayer as GeoJSONWorkerLayer} from '../GeoJSONWorkerLayer';
|
||||
import BoxHelper from '../../vendor/BoxHelper';
|
||||
import THREE from 'three';
|
||||
import reqwest from 'reqwest';
|
||||
import {point as Point} from '../../geo/Point';
|
||||
import {latLon as LatLon} from '../../geo/LatLon';
|
||||
import extend from 'lodash.assign';
|
||||
// import Offset from 'polygon-offset';
|
||||
import GeoJSON from '../../util/GeoJSON';
|
||||
import Buffer from '../../util/Buffer';
|
||||
import PickingMaterial from '../../engine/PickingMaterial';
|
||||
|
||||
// TODO: Map picking IDs to some reference within the tile data / geometry so
|
||||
// that something useful can be done when an object is picked / clicked on
|
||||
|
||||
// TODO: Make sure nothing is left behind in the heap after calling destroy()
|
||||
|
||||
// TODO: Perform tile request and processing in a Web Worker
|
||||
//
|
||||
// Use Operative (https://github.com/padolsey/operative)
|
||||
//
|
||||
// Would it make sense to have the worker functionality defined in a static
|
||||
// method so it only gets initialised once and not on every tile instance?
|
||||
//
|
||||
// Otherwise, worker processing logic would have to go in the tile layer so not
|
||||
// to waste loads of time setting up a brand new worker with three.js for each
|
||||
// tile every single time.
|
||||
//
|
||||
// Unsure of the best way to get three.js and VIZI into the worker
|
||||
//
|
||||
// Would need to set up a CRS / projection identical to the world instance
|
||||
//
|
||||
// Is it possible to bypass requirements on external script by having multiple
|
||||
// simple worker methods that each take enough inputs to perform a single task
|
||||
// without requiring VIZI or three.js? So long as the heaviest logic is done in
|
||||
// the worker and transferrable objects are used then it should be better than
|
||||
// nothing. Would probably still need things like earcut...
|
||||
//
|
||||
// After all, the three.js logic and object creation will still need to be
|
||||
// done on the main thread regardless so the worker should try to do as much as
|
||||
// possible with as few dependencies as possible.
|
||||
//
|
||||
// Have a look at how this is done in Tangram before implementing anything as
|
||||
// the approach there is pretty similar and robust.
|
||||
|
||||
class GeoJSONWorkerTile extends Tile {
|
||||
constructor(quadcode, path, layer, options) {
|
||||
super(quadcode, path, layer);
|
||||
|
||||
this._defaultStyle = GeoJSON.defaultStyle;
|
||||
|
||||
var defaults = {
|
||||
output: true,
|
||||
outputToScene: false,
|
||||
interactive: false,
|
||||
topojson: false,
|
||||
filter: null,
|
||||
onEachFeature: null,
|
||||
polygonMaterial: null,
|
||||
onPolygonMesh: null,
|
||||
onPolygonBufferAttributes: null,
|
||||
polylineMaterial: null,
|
||||
onPolylineMesh: null,
|
||||
onPolylineBufferAttributes: null,
|
||||
pointGeometry: null,
|
||||
pointMaterial: null,
|
||||
onPointMesh: null,
|
||||
style: GeoJSON.defaultStyle,
|
||||
keepFeatures: false
|
||||
};
|
||||
|
||||
var _options = extend({}, defaults, options);
|
||||
|
||||
if (typeof options.style === 'function') {
|
||||
_options.style = options.style;
|
||||
} else {
|
||||
_options.style = extend({}, defaults.style, options.style);
|
||||
}
|
||||
|
||||
this._options = _options;
|
||||
}
|
||||
|
||||
// Request data for the tile
|
||||
requestTileAsync() {
|
||||
// Making this asynchronous really speeds up the LOD framerate
|
||||
setTimeout(() => {
|
||||
if (!this._mesh) {
|
||||
this._mesh = this._createMesh();
|
||||
|
||||
// this._shadowCanvas = this._createShadowCanvas();
|
||||
|
||||
this._requestTile();
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
|
||||
// TODO: Destroy GeoJSONLayer
|
||||
destroy() {
|
||||
// Cancel any pending requests
|
||||
this._abortRequest();
|
||||
|
||||
// Clear request reference
|
||||
this._request = null;
|
||||
|
||||
if (this._geojsonLayer) {
|
||||
this._geojsonLayer.destroy();
|
||||
this._geojsonLayer = null;
|
||||
}
|
||||
|
||||
this._mesh = null;
|
||||
|
||||
// TODO: Properly dispose of picking mesh
|
||||
this._pickingMesh = null;
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
_createMesh() {
|
||||
// Something went wrong and the tile
|
||||
//
|
||||
// Possibly removed by the cache before loaded
|
||||
if (!this._center) {
|
||||
return;
|
||||
}
|
||||
|
||||
var mesh = new THREE.Object3D();
|
||||
// mesh.add(this._createDebugMesh());
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
_createDebugMesh() {
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = 256;
|
||||
canvas.height = 256;
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
context.font = 'Bold 20px Helvetica Neue, Verdana, Arial';
|
||||
context.fillStyle = '#ff0000';
|
||||
context.fillText(this._quadcode, 20, canvas.width / 2 - 5);
|
||||
context.fillText(this._tile.toString(), 20, canvas.width / 2 + 25);
|
||||
|
||||
var texture = new THREE.Texture(canvas);
|
||||
|
||||
// Silky smooth images when tilted
|
||||
texture.magFilter = THREE.LinearFilter;
|
||||
texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
|
||||
// TODO: Set this to renderer.getMaxAnisotropy() / 4
|
||||
texture.anisotropy = 4;
|
||||
|
||||
texture.needsUpdate = true;
|
||||
|
||||
var material = new THREE.MeshBasicMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
depthWrite: false
|
||||
});
|
||||
|
||||
var geom = new THREE.PlaneBufferGeometry(this._side, this._side, 1);
|
||||
var mesh = new THREE.Mesh(geom, material);
|
||||
|
||||
mesh.rotation.x = -90 * Math.PI / 180;
|
||||
mesh.position.y = 0.1;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
// _createShadowCanvas() {
|
||||
// var canvas = document.createElement('canvas');
|
||||
//
|
||||
// // Rendered at a low resolution and later scaled up for a low-quality blur
|
||||
// canvas.width = 512;
|
||||
// canvas.height = 512;
|
||||
//
|
||||
// return canvas;
|
||||
// }
|
||||
|
||||
// _addShadow(coordinates) {
|
||||
// var ctx = this._shadowCanvas.getContext('2d');
|
||||
// var width = this._shadowCanvas.width;
|
||||
// var height = this._shadowCanvas.height;
|
||||
//
|
||||
// var _coords;
|
||||
// var _offset;
|
||||
// var offset = new Offset();
|
||||
//
|
||||
// // Transform coordinates to shadowCanvas space and draw on canvas
|
||||
// coordinates.forEach((ring, index) => {
|
||||
// ctx.beginPath();
|
||||
//
|
||||
// _coords = ring.map(coord => {
|
||||
// var xFrac = (coord[0] - this._boundsWorld[0]) / this._side;
|
||||
// var yFrac = (coord[1] - this._boundsWorld[3]) / this._side;
|
||||
// return [xFrac * width, yFrac * height];
|
||||
// });
|
||||
//
|
||||
// if (index > 0) {
|
||||
// _offset = _coords;
|
||||
// } else {
|
||||
// _offset = offset.data(_coords).padding(1.3);
|
||||
// }
|
||||
//
|
||||
// // TODO: This is super flaky and crashes the browser if run on anything
|
||||
// // put the outer ring (potentially due to winding)
|
||||
// _offset.forEach((coord, index) => {
|
||||
// // var xFrac = (coord[0] - this._boundsWorld[0]) / this._side;
|
||||
// // var yFrac = (coord[1] - this._boundsWorld[3]) / this._side;
|
||||
//
|
||||
// if (index === 0) {
|
||||
// ctx.moveTo(coord[0], coord[1]);
|
||||
// } else {
|
||||
// ctx.lineTo(coord[0], coord[1]);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// ctx.closePath();
|
||||
// });
|
||||
//
|
||||
// ctx.fillStyle = 'rgba(80, 80, 80, 0.7)';
|
||||
// ctx.fill();
|
||||
// }
|
||||
|
||||
_requestTile() {
|
||||
var urlParams = {
|
||||
x: this._tile[0],
|
||||
y: this._tile[1],
|
||||
z: this._tile[2]
|
||||
};
|
||||
|
||||
var url = this._getTileURL(urlParams);
|
||||
|
||||
// this._request = reqwest({
|
||||
// url: url,
|
||||
// type: 'json',
|
||||
// crossOrigin: true
|
||||
// }).then(res => {
|
||||
// // Clear request reference
|
||||
// this._request = null;
|
||||
// this._processTileData(res);
|
||||
// }).catch(err => {
|
||||
// console.error(err);
|
||||
|
||||
// // Clear request reference
|
||||
// this._request = null;
|
||||
// });
|
||||
|
||||
this._processTileData(url);
|
||||
}
|
||||
|
||||
_processTileData(data) {
|
||||
console.time(this._tile);
|
||||
|
||||
// Using this creates a huge amount of memory due to the quantity of tiles
|
||||
var geojsonLayer = GeoJSONWorkerLayer(data, this._options);
|
||||
geojsonLayer.addTo(this._world).then(() => {
|
||||
this._geojsonLayer = geojsonLayer;
|
||||
this._mesh = this._geojsonLayer._object3D;
|
||||
this._pickingMesh = this._geojsonLayer._pickingMesh;
|
||||
|
||||
// Free the GeoJSON memory as we don't need it
|
||||
//
|
||||
// TODO: This should probably be a method within GeoJSONLayer
|
||||
// WORKERS: Disabled for now as it's needed with sync promises
|
||||
// this._geojsonLayer._geojson = null;
|
||||
|
||||
// TODO: Fix or store shadow canvas stuff and get rid of this code
|
||||
// Draw footprint on shadow canvas
|
||||
//
|
||||
// TODO: Disabled for the time-being until it can be sped up / moved to
|
||||
// a worker
|
||||
// this._addShadow(coordinates);
|
||||
|
||||
// Output shadow canvas
|
||||
|
||||
// TODO: Disabled for the time-being until it can be sped up / moved to
|
||||
// a worker
|
||||
|
||||
// var texture = new THREE.Texture(this._shadowCanvas);
|
||||
//
|
||||
// // Silky smooth images when tilted
|
||||
// texture.magFilter = THREE.LinearFilter;
|
||||
// texture.minFilter = THREE.LinearMipMapLinearFilter;
|
||||
//
|
||||
// // TODO: Set this to renderer.getMaxAnisotropy() / 4
|
||||
// texture.anisotropy = 4;
|
||||
//
|
||||
// texture.needsUpdate = true;
|
||||
//
|
||||
// var material;
|
||||
// if (!this._world._environment._skybox) {
|
||||
// material = new THREE.MeshBasicMaterial({
|
||||
// map: texture,
|
||||
// transparent: true,
|
||||
// depthWrite: false
|
||||
// });
|
||||
// } else {
|
||||
// material = new THREE.MeshStandardMaterial({
|
||||
// map: texture,
|
||||
// transparent: true,
|
||||
// depthWrite: false
|
||||
// });
|
||||
// material.roughness = 1;
|
||||
// material.metalness = 0.1;
|
||||
// material.envMap = this._world._environment._skybox.getRenderTarget();
|
||||
// }
|
||||
//
|
||||
// var geom = new THREE.PlaneBufferGeometry(this._side, this._side, 1);
|
||||
// var mesh = new THREE.Mesh(geom, material);
|
||||
//
|
||||
// mesh.castShadow = false;
|
||||
// mesh.receiveShadow = false;
|
||||
// mesh.renderOrder = 1;
|
||||
//
|
||||
// mesh.rotation.x = -90 * Math.PI / 180;
|
||||
//
|
||||
// this._mesh.add(mesh);
|
||||
|
||||
this._ready = true;
|
||||
console.timeEnd(this._tile);
|
||||
});
|
||||
}
|
||||
|
||||
_abortRequest() {
|
||||
if (!this._request) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._request.abort();
|
||||
}
|
||||
}
|
||||
|
||||
export default GeoJSONWorkerTile;
|
||||
|
||||
var noNew = function(quadcode, path, layer, options) {
|
||||
return new GeoJSONWorkerTile(quadcode, path, layer, options);
|
||||
};
|
||||
|
||||
// Initialise without requiring new keyword
|
||||
export {noNew as geoJSONWorkerTile};
|
|
@ -0,0 +1,158 @@
|
|||
import TileLayer from './TileLayer';
|
||||
import extend from 'lodash.assign';
|
||||
import GeoJSONWorkerTile from './GeoJSONWorkerTile';
|
||||
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 GeoJSONWorkerTileLayer extends TileLayer {
|
||||
constructor(path, options) {
|
||||
var defaults = {
|
||||
maxLOD: 14,
|
||||
distance: 30000
|
||||
};
|
||||
|
||||
options = extend({}, defaults, options);
|
||||
|
||||
super(options);
|
||||
|
||||
this._path = path;
|
||||
}
|
||||
|
||||
_onAdd(world) {
|
||||
return 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);
|
||||
});
|
||||
}
|
||||
|
||||
_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 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;
|
||||
// }
|
||||
//
|
||||
// if (this._options.interactive) {
|
||||
// options.interactive = true;
|
||||
// }
|
||||
//
|
||||
// if (this._options.onClick) {
|
||||
// options.onClick = this._options.onClick;
|
||||
// }
|
||||
|
||||
var workerTile = new GeoJSONWorkerTile(quadcode, this._path, layer, this._options);
|
||||
|
||||
// workerTile.on('click', (properties, point2d, point3d, intersects) => {
|
||||
// console.log(properties, point2d, point3d, intersects);
|
||||
// });
|
||||
|
||||
// workerTile.on('hover', (properties, point2d, point3d, intersects) => {
|
||||
|
||||
// });
|
||||
|
||||
return workerTile;
|
||||
}
|
||||
|
||||
// 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 GeoJSONWorkerTileLayer;
|
||||
|
||||
var noNew = function(path, options) {
|
||||
return new GeoJSONWorkerTileLayer(path, options);
|
||||
};
|
||||
|
||||
// Initialise without requiring new keyword
|
||||
export {noNew as geoJSONWorkerTileLayer};
|
|
@ -0,0 +1,22 @@
|
|||
import GeoJSONWorkerTileLayer from './GeoJSONWorkerTileLayer';
|
||||
import extend from 'lodash.assign';
|
||||
|
||||
class TopoJSONWorkerTileLayer extends GeoJSONWorkerTileLayer {
|
||||
constructor(path, options) {
|
||||
var defaults = {
|
||||
topojson: true
|
||||
};
|
||||
|
||||
options = extend({}, defaults, options);
|
||||
|
||||
super(path, options);
|
||||
}
|
||||
}
|
||||
|
||||
export default TopoJSONWorkerTileLayer;
|
||||
|
||||
var noNew = function(path, options) {
|
||||
return new TopoJSONWorkerTileLayer(path, options);
|
||||
};
|
||||
|
||||
export {noNew as topoJSONWorkerTileLayer};
|
|
@ -8,6 +8,8 @@ import EnvironmentLayer, {environmentLayer} from './layer/environment/Environmen
|
|||
import ImageTileLayer, {imageTileLayer} from './layer/tile/ImageTileLayer';
|
||||
import GeoJSONTileLayer, {geoJSONTileLayer} from './layer/tile/GeoJSONTileLayer';
|
||||
import TopoJSONTileLayer, {topoJSONTileLayer} from './layer/tile/TopoJSONTileLayer';
|
||||
import GeoJSONWorkerTileLayer, {geoJSONWorkerTileLayer} from './layer/tile/GeoJSONWorkerTileLayer';
|
||||
import TopoJSONWorkerTileLayer, {topoJSONWorkerTileLayer} from './layer/tile/TopoJSONWorkerTileLayer';
|
||||
import GeoJSONLayer, {geoJSONLayer} from './layer/GeoJSONLayer';
|
||||
import TopoJSONLayer, {topoJSONLayer} from './layer/TopoJSONLayer';
|
||||
import GeoJSONWorkerLayer, {geoJSONWorkerLayer} from './layer/GeoJSONWorkerLayer';
|
||||
|
@ -41,6 +43,10 @@ const VIZI = {
|
|||
geoJSONTileLayer: geoJSONTileLayer,
|
||||
TopoJSONTileLayer: TopoJSONTileLayer,
|
||||
topoJSONTileLayer: topoJSONTileLayer,
|
||||
GeoJSONWorkerTileLayer: GeoJSONWorkerTileLayer,
|
||||
geoJSONWorkerTileLayer: geoJSONWorkerTileLayer,
|
||||
TopoJSONWorkerTileLayer: TopoJSONWorkerTileLayer,
|
||||
topoJSONWorkerTileLayer: topoJSONWorkerTileLayer,
|
||||
GeoJSONLayer: GeoJSONLayer,
|
||||
geoJSONLayer: geoJSONLayer,
|
||||
TopoJSONLayer: TopoJSONLayer,
|
||||
|
|
Ładowanie…
Reference in New Issue