Merge pull request #183 from UDST/feature/tile-display-bug

Initial fix for tile duplication bug
feature/threejs-update
Robin Hawkes 2016-10-06 11:17:35 +01:00 zatwierdzone przez GitHub
commit 06de12be9d
7 zmienionych plików z 484 dodań i 372 usunięć

Wyświetl plik

@ -242,6 +242,8 @@ class World extends EventEmitter {
}
addLayer(layer) {
// Is is right to assume that there will always be some other layer
// managing layers with output set to false?
this._layers.push(layer);
if (layer.isOutput() && layer.isOutputToScene()) {
@ -256,7 +258,11 @@ class World extends EventEmitter {
if (layer._options.attribution) {
this._addAttribution(layer._options.id, layer._options.attribution);
}
// TODO: Consider moving this so it doesn't fire for layers that are
// actually managed by a parent layer (eg. tiles)
this.emit('layerAdded', layer);
resolve(this);
}).catch(reject);
});

Wyświetl plik

@ -38,6 +38,7 @@ class GeoJSONWorkerLayer extends Layer {
super(_options);
this._aborted = false;
this._geojson = geojson;
}
@ -80,6 +81,11 @@ class GeoJSONWorkerLayer extends Layer {
}).catch(reject);
} else if (typeof this._options.filter === 'function' || typeof this._options.onEachFeature === 'function') {
GeoJSONWorkerLayer.RequestGeoJSON(geojson).then((res) => {
// if (this._aborted) {
// resolve();
// return;
// }
var fc = GeoJSON.collectFeatures(res, this._options.topojson);
var features = fc.features;
@ -118,16 +124,198 @@ class GeoJSONWorkerLayer extends Layer {
Worker.exec('GeoJSONWorkerLayer.Process', [geojson, topojson, headers, originPoint, style, interactive, pointGeometry], transferrables).then((results) => {
console.timeEnd('Worker round trip');
// if (this._aborted) {
// resolve();
// return;
// }
var processPromises = [];
if (results.polygons) {
this._processPolygonResults(results.polygons);
processPromises.push(this._processPolygonResults(results.polygons));
}
if (results.polylines) {
this._processPolylineResults(results.polylines);
processPromises.push(this._processPolylineResults(results.polylines));
}
if (results.points) {
this._processPointResults(results.points);
processPromises.push(this._processPointResults(results.points));
}
if (processPromises.length > 0) {
Promise.all(processPromises).then(() => {
resolve();
});
} else {
resolve();
}
});
});
}
// TODO: Dedupe with polyline method
_processPolygonResults(results) {
return new Promise((resolve, reject) => {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
var splitTops = Buffer.splitFloat32Array(results.attributes.tops);
var splitOutlinePositions;
var splitOutlineColors;
if (results.outlineAttributes) {
splitOutlinePositions = Buffer.splitFloat32Array(results.outlineAttributes.positions);
splitOutlineColors = Buffer.splitFloat32Array(results.outlineAttributes.colors);
}
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
var flats = results.flats;
var objects = [];
var outlineObjects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var polygonAttributeLengths = {
positions: 3,
normals: 3,
colors: 3,
tops: 1
};
var polygonOutlineAttributeLengths = {
positions: 3,
colors: 3
};
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
normals: splitNormals[i],
colors: splitColors[i],
tops: splitTops[i]
}],
properties: properties,
flat: flats[i]
};
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
obj.attributes[0].pickingIds = pickingIds;
polygonAttributeLengths.pickingIds = 1;
this._addPicking(pickingId, properties);
}
// TODO: Make this specific to polygon attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
polygonAttributeLengths[key] = customAttribute.length;
}
}
objects.push(obj);
}
for (var i = 0; i < splitOutlinePositions.length; i++) {
obj = {
attributes: [{
positions: splitOutlinePositions[i],
colors: splitOutlineColors[i]
}],
flat: true
};
outlineObjects.push(obj);
}
var polygonAttributes = [];
var polygonOutlineAttributes = [];
var polygonFlat = true;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
if (polygonFlat && !obj.flat) {
polygonFlat = false;
}
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polygonAttributes.push(bufferAttributes);
};
for (var i = 0; i < outlineObjects.length; i++) {
obj = outlineObjects[i];
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polygonOutlineAttributes.push(bufferAttributes);
};
var outputPromises = [];
if (polygonAttributes.length > 0) {
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
outputPromises.push(this._setPolygonMesh(mergedPolygonAttributes, polygonAttributeLengths, style, polygonFlat));
}
if (polygonOutlineAttributes.length > 0) {
var mergedPolygonOutlineAttributes = Buffer.mergeAttributes(polygonOutlineAttributes);
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
outputPromises.push(this._setPolylineMesh(mergedPolygonOutlineAttributes, polygonOutlineAttributeLengths, style, true));
}
Promise.all(outputPromises).then((results) => {
var [polygonResult, outlineResult] = results;
if (polygonResult) {
this._polygonMesh = polygonResult.mesh;
this.add(this._polygonMesh);
if (polygonResult.pickingMesh) {
this._pickingMesh.add(polygonResult.pickingMesh);
}
}
if (outlineResult) {
this.add(outlineResult.mesh);
}
resolve();
@ -135,370 +323,224 @@ class GeoJSONWorkerLayer extends Layer {
});
}
// TODO: Dedupe with polyline method
_processPolygonResults(results) {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
var splitTops = Buffer.splitFloat32Array(results.attributes.tops);
var splitOutlinePositions;
var splitOutlineColors;
if (results.outlineAttributes) {
splitOutlinePositions = Buffer.splitFloat32Array(results.outlineAttributes.positions);
splitOutlineColors = Buffer.splitFloat32Array(results.outlineAttributes.colors);
}
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
var flats = results.flats;
var objects = [];
var outlineObjects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var polygonAttributeLengths = {
positions: 3,
normals: 3,
colors: 3,
tops: 1
};
var polygonOutlineAttributeLengths = {
positions: 3,
colors: 3
};
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
normals: splitNormals[i],
colors: splitColors[i],
tops: splitTops[i]
}],
properties: properties,
flat: flats[i]
};
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
obj.attributes[0].pickingIds = pickingIds;
polygonAttributeLengths.pickingIds = 1;
this._addPicking(pickingId, properties);
}
// TODO: Make this specific to polygon attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
polygonAttributeLengths[key] = customAttribute.length;
}
}
objects.push(obj);
}
for (var i = 0; i < splitOutlinePositions.length; i++) {
obj = {
attributes: [{
positions: splitOutlinePositions[i],
colors: splitOutlineColors[i]
}],
flat: true
};
outlineObjects.push(obj);
}
var polygonAttributes = [];
var polygonOutlineAttributes = [];
var polygonFlat = true;
var obj;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
if (polygonFlat && !obj.flat) {
polygonFlat = false;
}
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polygonAttributes.push(bufferAttributes);
};
for (var i = 0; i < outlineObjects.length; i++) {
obj = outlineObjects[i];
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polygonOutlineAttributes.push(bufferAttributes);
};
if (polygonAttributes.length > 0) {
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPolygonMesh(mergedPolygonAttributes, polygonAttributeLengths, style, polygonFlat).then((result) => {
this._polygonMesh = result.mesh;
this.add(this._polygonMesh);
if (result.pickingMesh) {
this._pickingMesh.add(result.pickingMesh);
}
});
}
if (polygonOutlineAttributes.length > 0) {
var mergedPolygonOutlineAttributes = Buffer.mergeAttributes(polygonOutlineAttributes);
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPolylineMesh(mergedPolygonOutlineAttributes, polygonOutlineAttributeLengths, style, true).then((result) => {
this.add(result.mesh);
});
}
}
// TODO: Dedupe with polygon method
_processPolylineResults(results) {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
return new Promise((resolve, reject) => {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
var flats = results.flats;
var objects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var polylineAttributeLengths = {
positions: 3,
colors: 3
};
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
colors: splitColors[i]
}],
properties: properties,
flat: flats[i]
var flats = results.flats;
var objects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var polylineAttributeLengths = {
positions: 3,
colors: 3
};
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
obj.attributes[0].pickingIds = pickingIds;
polylineAttributeLengths.pickingIds = 1;
this._addPicking(pickingId, properties);
}
// TODO: Make this specific to polyline attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
polylineAttributeLengths[key] = customAttribute.length;
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
}
}
objects.push(obj);
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
colors: splitColors[i]
}],
properties: properties,
flat: flats[i]
};
var polylineAttributes = [];
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
var polylineFlat = true;
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
var obj;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
obj.attributes[0].pickingIds = pickingIds;
if (polylineFlat && !obj.flat) {
polylineFlat = false;
}
polylineAttributeLengths.pickingIds = 1;
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polylineAttributes.push(bufferAttributes);
};
if (polylineAttributes.length > 0) {
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPolylineMesh(mergedPolylineAttributes, polylineAttributeLengths, style, polylineFlat).then((result) => {
this._polylineMesh = result.mesh;
this.add(this._polylineMesh);
if (result.pickingMesh) {
this._pickingMesh.add(result.pickingMesh);
this._addPicking(pickingId, properties);
}
});
}
// TODO: Make this specific to polyline attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
polylineAttributeLengths[key] = customAttribute.length;
}
}
objects.push(obj);
}
var polylineAttributes = [];
var polylineFlat = true;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
if (polylineFlat && !obj.flat) {
polylineFlat = false;
}
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
polylineAttributes.push(bufferAttributes);
};
if (polylineAttributes.length > 0) {
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPolylineMesh(mergedPolylineAttributes, polylineAttributeLengths, style, polylineFlat).then((result) => {
this._polylineMesh = result.mesh;
this.add(this._polylineMesh);
if (result.pickingMesh) {
this._pickingMesh.add(result.pickingMesh);
}
resolve();
});
} else {
resolve();
}
});
}
_processPointResults(results) {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
return new Promise((resolve, reject) => {
var splitPositions = Buffer.splitFloat32Array(results.attributes.positions);
var splitNormals = Buffer.splitFloat32Array(results.attributes.normals);
var splitColors = Buffer.splitFloat32Array(results.attributes.colors);
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
var flats = results.flats;
var objects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var pointAttributeLengths = {
positions: 3,
normals: 3,
colors: 3
};
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
var splitProperties;
if (results.properties) {
splitProperties = Buffer.splitUint8Array(results.properties);
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
normals: splitNormals[i],
colors: splitColors[i]
}],
properties: properties,
flat: flats[i]
var flats = results.flats;
var objects = [];
var obj;
var pickingId;
var pickingIds;
var properties;
var pointAttributeLengths = {
positions: 3,
normals: 3,
colors: 3
};
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
obj.attributes[0].pickingIds = pickingIds;
pointAttributeLengths.pickingIds = 1;
this._addPicking(pickingId, properties);
}
// TODO: Make this specific to polygon attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
pointAttributeLengths[key] = customAttribute.length;
for (var i = 0; i < splitPositions.length; i++) {
if (splitProperties && splitProperties[i]) {
properties = JSON.parse(Buffer.uint8ArrayToString(splitProperties[i]));
} else {
properties = {};
}
}
objects.push(obj);
}
// WORKERS: obj.attributes should actually an array of polygons for
// the feature, though the current logic isn't aware of that
obj = {
attributes: [{
positions: splitPositions[i],
normals: splitNormals[i],
colors: splitColors[i]
}],
properties: properties,
flat: flats[i]
};
var pointAttributes = [];
// WORKERS: If interactive, generate unique ID for each feature, create
// the buffer attributes and set up event listeners
if (this._options.interactive) {
pickingId = this.getPickingId();
var pointFlat = true;
pickingIds = new Float32Array(splitPositions[i].length / 3);
pickingIds.fill(pickingId);
var obj;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
obj.attributes[0].pickingIds = pickingIds;
if (pointFlat && !obj.flat) {
pointFlat = false;
}
pointAttributeLengths.pickingIds = 1;
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
pointAttributes.push(bufferAttributes);
};
if (pointAttributes.length > 0) {
var mergedPointAttributes = Buffer.mergeAttributes(pointAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPointMesh(mergedPointAttributes, pointAttributeLengths, style, pointFlat).then((result) => {
this._pointMesh = result.mesh;
this.add(this._pointMesh);
if (result.pickingMesh) {
this._pickingMesh.add(result.pickingMesh);
this._addPicking(pickingId, properties);
}
});
}
// TODO: Make this specific to polygon attributes
if (typeof this._options.onAddAttributes === 'function') {
var customAttributes = this._options.onAddAttributes(obj.attributes[0], properties);
var customAttribute;
for (var key in customAttributes) {
customAttribute = customAttributes[key];
obj.attributes[0][key] = customAttribute.value;
pointAttributeLengths[key] = customAttribute.length;
}
}
objects.push(obj);
}
var pointAttributes = [];
var pointFlat = true;
for (var i = 0; i < objects.length; i++) {
obj = objects[i];
if (pointFlat && !obj.flat) {
pointFlat = false;
}
var bufferAttributes = Buffer.mergeAttributes(obj.attributes);
pointAttributes.push(bufferAttributes);
};
if (pointAttributes.length > 0) {
var mergedPointAttributes = Buffer.mergeAttributes(pointAttributes);
// TODO: Make this work when style is a function per feature
var style = (typeof this._options.style === 'function') ? this._options.style(objects[0]) : this._options.style;
style = extend({}, GeoJSON.defaultStyle, style);
this._setPointMesh(mergedPointAttributes, pointAttributeLengths, style, pointFlat).then((result) => {
this._pointMesh = result.mesh;
this.add(this._pointMesh);
if (result.pickingMesh) {
this._pickingMesh.add(result.pickingMesh);
}
resolve();
});
} else {
resolve();
}
});
}
// TODO: At some point this needs to return all the features to the main thread

Wyświetl plik

@ -89,11 +89,10 @@ class GeoJSONTile extends Tile {
setTimeout(() => {
if (!this._mesh) {
this._mesh = this._createMesh();
// this._shadowCanvas = this._createShadowCanvas();
this._requestTile();
}
this._requestTile();
}, 0);
}
@ -233,6 +232,8 @@ class GeoJSONTile extends Tile {
var url = this._getTileURL(urlParams);
this._aborted = false;
if (!this._options.workers) {
this._request = reqwest({
url: url,
@ -244,8 +245,6 @@ class GeoJSONTile extends Tile {
this._request = null;
this._processTileData(res);
}).catch(err => {
console.error(err);
// Clear request reference
this._request = null;
});
@ -255,13 +254,37 @@ class GeoJSONTile extends Tile {
}
_processTileData(data) {
console.time(this._tile);
// console.time(this._tile);
var GeoJSONClass = (!this._options.workers) ? GeoJSONLayer : GeoJSONWorkerLayer;
// Using this creates a huge amount of memory due to the quantity of tiles
this._geojsonLayer = GeoJSONClass(data, this._options);
this._geojsonLayer.addTo(this._world).then(() => {
// TODO: This never seems to be called on worker layers. Find out why.
if (this.isAborted()) {
// this._geojsonLayer._aborted = true;
// this._geojsonLayer = null;
return;
}
// TODO: This is a hack to stop old tile meshes hanging around. Fix or
// move to somewhere more robust.
//
// Could potentially just overwrite mesh on first index each time
//
// This makes some worker tiles to not appear properly – showing the
// points mesh but not the polygon mesh, etc.
//
// Only do this for non-worker layers for now as it seems to cause issues
// with worker tiles showing for a moment and then disappearing forever
if (!this._options.workers) {
this.destroyMesh(this._mesh);
}
// TOSO: Work out if the picking mesh needs destroying here
// this.destroyMesh(this._pickingMesh);
this._mesh.add(this._geojsonLayer._object3D);
this._pickingMesh = this._geojsonLayer._pickingMesh;
@ -325,16 +348,20 @@ class GeoJSONTile extends Tile {
// this._mesh.add(mesh);
this._ready = true;
console.timeEnd(this._tile);
// console.timeEnd(this._tile);
});
}
_abortRequest() {
if (!this._request) {
if ((!this._request && !this._options.workers) || this._ready) {
return;
}
this._request.abort();
this._aborted = true;
if (this._request) {
this._request.abort();
}
}
}

Wyświetl plik

@ -108,7 +108,10 @@ class GeoJSONTileLayer extends TileLayer {
}
_createTile(quadcode, layer) {
var newOptions = extend({}, this.defaults, this._options);
var newOptions = extend({}, this.defaults, this._options, {
outputToScene: false
});
delete newOptions.attribution;
return new GeoJSONTile(quadcode, this._path, layer, newOptions);

Wyświetl plik

@ -15,8 +15,9 @@ class ImageTile extends Tile {
setTimeout(() => {
if (!this._mesh) {
this._mesh = this._createMesh();
this._requestTile();
}
this._requestTile();
}, 0);
}
@ -131,7 +132,13 @@ class ImageTile extends Tile {
var image = document.createElement('img');
this._aborted = false;
image.addEventListener('load', event => {
if (this.isAborted()) {
return;
}
var texture = new THREE.Texture();
texture.image = image;
@ -172,10 +179,12 @@ class ImageTile extends Tile {
}
_abortRequest() {
if (!this._image) {
if (!this._image || this._ready) {
return;
}
this._aborted = true;
this._image.src = '';
}
}

Wyświetl plik

@ -18,6 +18,7 @@ class Tile {
this._path = path;
this._ready = false;
this._aborted = false;
this._tile = this._quadcodeToTile(quadcode);
@ -46,6 +47,10 @@ class Tile {
return this._ready;
}
isAborted() {
return this._aborted;
}
// Request data for the tile
requestTileAsync() {}
@ -78,6 +83,8 @@ class Tile {
// Ensure that this leaves no trace of the tile – no textures, no meshes,
// nothing in memory or the GPU
destroy() {
// console.log('Destroying tile', this._quadcode);
// Delete reference to layer and world
this._layer = null;
this._world = null;
@ -88,35 +95,42 @@ class Tile {
this._center = null;
// Done if no mesh
if (!this._mesh) {
if (!this._mesh && !this._pickingMesh) {
return;
}
if (this._mesh.children) {
// Dispose of mesh and materials
this._mesh.children.forEach(child => {
child.geometry.dispose();
child.geometry = null;
this.destroyMesh(this._mesh);
this.destroyMesh(this._pickingMesh);
if (child.material.map) {
child.material.map.dispose();
child.material.map = null;
}
this._mesh = null;
this._pickingMesh = null;
}
child.material.dispose();
child.material = null;
});
} else {
this._mesh.geometry.dispose();
this._mesh.geometry = null;
if (this._mesh.material.map) {
this._mesh.material.map.dispose();
this._mesh.material.map = null;
destroyMesh(mesh, dispose = true) {
if (mesh) {
if (mesh.children) {
mesh.children.forEach((child) => {
mesh.remove(child);
this.destroyMesh(child);
});
}
this._mesh.material.dispose();
this._mesh.material = null;
if (dispose) {
if (mesh.geometry) {
mesh.geometry.dispose();
mesh.geometry = null;
}
if (mesh.material) {
if (mesh.material.map) {
mesh.material.map.dispose();
mesh.material.map = null;
}
mesh.material.dispose();
mesh.material = null;
}
}
}
}

Wyświetl plik

@ -168,7 +168,7 @@ class TileLayer extends Layer {
});
// 5. Filter the tiles remaining in the check list
this._tileList = checkList.filter((tile, index) => {
var tileList = checkList.filter((tile, index) => {
// Skip tile if it's not in the current view frustum
if (!this._tileInFrustum(tile)) {
return false;
@ -189,7 +189,7 @@ class TileLayer extends Layer {
//
// If yes, continue
// If no, generate tile mesh, request texture and skip
if (!tile.getMesh()) {
if (!tile.getMesh() || tile.isAborted()) {
tile.requestTileAsync();
}
@ -207,6 +207,17 @@ class TileLayer extends Layer {
// this._tiles.add(tile.getMesh());
});
// Get list of tiles that were in the previous update but not the
// current one (for aborting requests, etc)
var missingTiles = this._tileList.filter((item) => {
return !tileList.includes(item);
});
// Abort tiles that are no longer in view
missingTiles.forEach((tile) => tile._abortRequest());
this._tileList = tileList;
// console.log(performance.now() - start);
}