Removed old GeoJSONLayer

master
Robin Hawkes 2016-03-08 15:38:11 +00:00
rodzic 3671cc6eb1
commit e134ee3768
7 zmienionych plików z 235 dodań i 1140 usunięć

528
dist/vizicities.js vendored
Wyświetl plik

@ -92,19 +92,15 @@ return /******/ (function(modules) { // webpackBootstrap
var _layerGeoJSONLayer2 = _interopRequireDefault(_layerGeoJSONLayer);
var _layerGeoJSONLayer22 = __webpack_require__(76);
var _layerGeoJSONLayer23 = _interopRequireDefault(_layerGeoJSONLayer22);
var _layerTopoJSONLayer = __webpack_require__(80);
var _layerTopoJSONLayer = __webpack_require__(79);
var _layerTopoJSONLayer2 = _interopRequireDefault(_layerTopoJSONLayer);
var _layerGeometryPolygonLayer = __webpack_require__(78);
var _layerGeometryPolygonLayer = __webpack_require__(77);
var _layerGeometryPolygonLayer2 = _interopRequireDefault(_layerGeometryPolygonLayer);
var _layerGeometryPolylineLayer = __webpack_require__(79);
var _layerGeometryPolylineLayer = __webpack_require__(78);
var _layerGeometryPolylineLayer2 = _interopRequireDefault(_layerGeometryPolylineLayer);
@ -135,8 +131,6 @@ return /******/ (function(modules) { // webpackBootstrap
topoJSONTileLayer: _layerTileTopoJSONTileLayer.topoJSONTileLayer,
GeoJSONLayer: _layerGeoJSONLayer2['default'],
geoJSONLayer: _layerGeoJSONLayer.geoJSONLayer,
GeoJSONLayer2: _layerGeoJSONLayer23['default'],
geoJSONLayer2: _layerGeoJSONLayer22.geoJSONLayer2,
TopoJSONLayer: _layerTopoJSONLayer2['default'],
topoJSONLayer: _layerTopoJSONLayer.topoJSONLayer,
PolygonLayer: _layerGeometryPolygonLayer2['default'],
@ -15844,481 +15838,7 @@ return /******/ (function(modules) { // webpackBootstrap
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _Layer2 = __webpack_require__(37);
var _Layer3 = _interopRequireDefault(_Layer2);
var _three = __webpack_require__(24);
var _three2 = _interopRequireDefault(_three);
var _reqwest = __webpack_require__(63);
var _reqwest2 = _interopRequireDefault(_reqwest);
var _lodashAssign = __webpack_require__(3);
var _lodashAssign2 = _interopRequireDefault(_lodashAssign);
var _geoPoint = __webpack_require__(11);
var _geoLatLon = __webpack_require__(10);
var _utilGeoJSON = __webpack_require__(65);
var _utilGeoJSON2 = _interopRequireDefault(_utilGeoJSON);
var _utilBuffer = __webpack_require__(71);
var _utilBuffer2 = _interopRequireDefault(_utilBuffer);
var _enginePickingMaterial = __webpack_require__(72);
var _enginePickingMaterial2 = _interopRequireDefault(_enginePickingMaterial);
var GeoJSONLayer = (function (_Layer) {
_inherits(GeoJSONLayer, _Layer);
function GeoJSONLayer(geojson, options) {
_classCallCheck(this, GeoJSONLayer);
var defaults = {
picking: false,
topojson: false,
filter: null,
onClick: null,
style: _utilGeoJSON2['default'].defaultStyle
};
var _options = (0, _lodashAssign2['default'])({}, defaults, options);
_get(Object.getPrototypeOf(GeoJSONLayer.prototype), 'constructor', this).call(this, _options);
if (typeof options.style === 'function') {
this._options.style = options.style;
} else {
this._options.style = (0, _lodashAssign2['default'])({}, defaults.style, options.style);
}
this._defaultStyle = _utilGeoJSON2['default'].defaultStyle;
this._geojson = geojson;
this._pickingMesh = new _three2['default'].Object3D();
}
_createClass(GeoJSONLayer, [{
key: '_onAdd',
value: function _onAdd(world) {
this.addToPicking(this._pickingMesh);
// Request data from URL if needed
if (typeof this._geojson === 'string') {
this._requestData(this._geojson);
} else {
// Process and add GeoJSON to layer
this._processData(this._geojson);
}
}
}, {
key: '_requestData',
value: function _requestData(url) {
var _this = this;
this._request = (0, _reqwest2['default'])({
url: url,
type: 'json',
crossOrigin: true
}).then(function (res) {
// Clear request reference
_this._request = null;
_this._processData(res);
})['catch'](function (err) {
console.error(err);
// Clear request reference
_this._request = null;
});
}
}, {
key: '_processData',
value: function _processData(data) {
var _this2 = this;
console.time('GeoJSON');
var geojson = _utilGeoJSON2['default'].collectFeatures(data, this._options.topojson);
// TODO: Check that GeoJSON is valid / usable
var features = geojson.features;
// Run filter, if provided
if (this._options.filter) {
features = geojson.features.filter(this._options.filter);
}
var style = this._options.style;
var offset;
// TODO: Wrap into a helper method so this isn't duplicated in the tiled
// GeoJSON output layer
//
// Need to be careful as to not make it impossible to fork this off into a
// worker script at a later stage
//
// Also unsure as to whether it's wise to lump so much into a black box
//
// var meshes = GeoJSON.createMeshes(features, offset, style);
var polygons = {
vertices: [],
faces: [],
colours: [],
facesCount: 0,
allFlat: true
};
var lines = {
vertices: [],
colours: [],
verticesCount: 0
};
if (this._options.picking) {
polygons.pickingIds = [];
lines.pickingIds = [];
}
var colour = new _three2['default'].Color();
features.forEach(function (feature) {
// feature.geometry, feature.properties
// Skip features that aren't supported
//
// TODO: Add support for all GeoJSON geometry types, including Multi...
// geometry types
if (feature.geometry.type !== 'Polygon' && feature.geometry.type !== 'LineString' && feature.geometry.type !== 'MultiLineString') {
return;
}
// Get style object, if provided
if (typeof _this2._options.style === 'function') {
style = (0, _lodashAssign2['default'])(_this2._defaultStyle, _this2._options.style(feature));
}
var coordinates = feature.geometry.coordinates;
// if (feature.geometry.type === 'LineString') {
if (feature.geometry.type === 'LineString') {
colour.set(style.lineColor);
coordinates = coordinates.map(function (coordinate) {
var latlon = (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
var point = _this2._world.latLonToPoint(latlon);
if (!offset) {
offset = (0, _geoPoint.point)(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
_this2._pointScale = _this2._world.pointScale(latlon);
}
return [point.x, point.y];
});
var height = 0;
if (style.lineHeight) {
height = _this2._world.metresToWorld(style.lineHeight, _this2._pointScale);
}
var linestringAttributes = _utilGeoJSON2['default'].lineStringAttributes(coordinates, colour, height);
lines.vertices.push(linestringAttributes.vertices);
lines.colours.push(linestringAttributes.colours);
if (_this2._options.picking) {
var pickingId = _this2.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
lines.pickingIds.push(pickingId);
if (_this2._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
_this2._world.on('pick-' + pickingId, function (point2d, point3d, intersects) {
_this2._options.onClick(feature, point2d, point3d, intersects);
});
}
}
lines.verticesCount += linestringAttributes.vertices.length;
}
if (feature.geometry.type === 'MultiLineString') {
colour.set(style.lineColor);
coordinates = coordinates.map(function (_coordinates) {
return _coordinates.map(function (coordinate) {
var latlon = (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
var point = _this2._world.latLonToPoint(latlon);
if (!offset) {
offset = (0, _geoPoint.point)(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
_this2._pointScale = _this2._world.pointScale(latlon);
}
return [point.x, point.y];
});
});
var height = 0;
if (style.lineHeight) {
height = _this2._world.metresToWorld(style.lineHeight, _this2._pointScale);
}
var multiLinestringAttributes = _utilGeoJSON2['default'].multiLineStringAttributes(coordinates, colour, height);
lines.vertices.push(multiLinestringAttributes.vertices);
lines.colours.push(multiLinestringAttributes.colours);
if (_this2._options.picking) {
var pickingId = _this2.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
lines.pickingIds.push(pickingId);
if (_this2._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
_this2._world.on('pick-' + pickingId, function (point2d, point3d, intersects) {
_this2._options.onClick(feature, point2d, point3d, intersects);
});
}
}
lines.verticesCount += multiLinestringAttributes.vertices.length;
}
if (feature.geometry.type === 'Polygon') {
colour.set(style.color);
coordinates = coordinates.map(function (ring) {
return ring.map(function (coordinate) {
var latlon = (0, _geoLatLon.latLon)(coordinate[1], coordinate[0]);
var point = _this2._world.latLonToPoint(latlon);
if (!offset) {
offset = (0, _geoPoint.point)(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
_this2._pointScale = _this2._world.pointScale(latlon);
}
return [point.x, point.y];
});
});
var height = 0;
if (style.height) {
height = _this2._world.metresToWorld(style.height, _this2._pointScale);
}
var polygonAttributes = _utilGeoJSON2['default'].polygonAttributes(coordinates, colour, height);
polygons.vertices.push(polygonAttributes.vertices);
polygons.faces.push(polygonAttributes.faces);
polygons.colours.push(polygonAttributes.colours);
if (_this2._options.picking) {
var pickingId = _this2.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
polygons.pickingIds.push(pickingId);
if (_this2._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
_this2._world.on('pick-' + pickingId, function (point2d, point3d, intersects) {
_this2._options.onClick(feature, point2d, point3d, intersects);
});
}
}
if (polygons.allFlat && !polygonAttributes.flat) {
polygons.allFlat = false;
}
polygons.facesCount += polygonAttributes.faces.length;
}
});
var geometry;
var material;
var mesh;
if (this._options.picking) {
// Move picking mesh to origin Point
this._pickingMesh.position.x = -offset.x;
this._pickingMesh.position.z = -offset.y;
}
// Output lines
if (lines.vertices.length > 0) {
geometry = _utilBuffer2['default'].createLineGeometry(lines, offset);
material = new _three2['default'].LineBasicMaterial({
vertexColors: _three2['default'].VertexColors,
linewidth: style.lineWidth,
transparent: style.lineTransparent,
opacity: style.lineOpacity,
blending: style.lineBlending
});
mesh = new _three2['default'].LineSegments(geometry, material);
if (style.lineRenderOrder !== undefined) {
material.depthWrite = false;
mesh.renderOrder = style.lineRenderOrder;
}
// TODO: Can a line cast a shadow?
// mesh.castShadow = true;
this.add(mesh);
if (this._options.picking) {
material = new _enginePickingMaterial2['default']();
material.side = _three2['default'].BackSide;
// Make the line wider / easier to pick
material.linewidth = style.lineWidth + material.linePadding;
var pickingMesh = new _three2['default'].LineSegments(geometry, material);
this._pickingMesh.add(pickingMesh);
}
}
// Output polygons
if (polygons.facesCount > 0) {
geometry = _utilBuffer2['default'].createGeometry(polygons, offset);
if (!this._world._environment._skybox) {
material = new _three2['default'].MeshPhongMaterial({
vertexColors: _three2['default'].VertexColors,
side: _three2['default'].BackSide
});
} else {
material = new _three2['default'].MeshStandardMaterial({
vertexColors: _three2['default'].VertexColors,
side: _three2['default'].BackSide
});
material.roughness = 1;
material.metalness = 0.1;
material.envMapIntensity = 3;
material.envMap = this._world._environment._skybox.getRenderTarget();
}
mesh = new _three2['default'].Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
if (polygons.allFlat) {
material.depthWrite = false;
mesh.renderOrder = 1;
}
this.add(mesh);
if (this._options.picking) {
material = new _enginePickingMaterial2['default']();
material.side = _three2['default'].BackSide;
var pickingMesh = new _three2['default'].Mesh(geometry, material);
this._pickingMesh.add(pickingMesh);
}
}
// Move layer to origin Point
//
// TODO: Is there a better way to ensure everything is aligned right and
// able to be frustum-culled?
this._object3D.position.x = -offset.x;
this._object3D.position.z = -offset.y;
console.timeEnd('GeoJSON');
}
}, {
key: '_abortRequest',
value: function _abortRequest() {
if (!this._request) {
return;
}
this._request.abort();
}
}, {
key: 'destroy',
value: function destroy() {
// Cancel any pending requests
this._abortRequest();
// Clear request reference
this._request = null;
// TODO: Properly dispose of picking mesh
this._pickingMesh = null;
// Run common destruction logic from parent
_get(Object.getPrototypeOf(GeoJSONLayer.prototype), 'destroy', this).call(this);
}
}]);
return GeoJSONLayer;
})(_Layer3['default']);
exports['default'] = GeoJSONLayer;
var noNew = function noNew(geojson, options) {
return new GeoJSONLayer(geojson, options);
};
// Initialise without requiring new keyword
exports.geoJSONLayer = noNew;
/***/ },
/* 76 */
/***/ function(module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var _LayerGroup2 = __webpack_require__(77);
var _LayerGroup2 = __webpack_require__(76);
var _LayerGroup3 = _interopRequireDefault(_LayerGroup2);
@ -16342,19 +15862,19 @@ return /******/ (function(modules) { // webpackBootstrap
var _enginePickingMaterial2 = _interopRequireDefault(_enginePickingMaterial);
var _geometryPolygonLayer = __webpack_require__(78);
var _geometryPolygonLayer = __webpack_require__(77);
var _geometryPolygonLayer2 = _interopRequireDefault(_geometryPolygonLayer);
var _geometryPolylineLayer = __webpack_require__(79);
var _geometryPolylineLayer = __webpack_require__(78);
var _geometryPolylineLayer2 = _interopRequireDefault(_geometryPolylineLayer);
var GeoJSONLayer2 = (function (_LayerGroup) {
_inherits(GeoJSONLayer2, _LayerGroup);
var GeoJSONLayer = (function (_LayerGroup) {
_inherits(GeoJSONLayer, _LayerGroup);
function GeoJSONLayer2(geojson, options) {
_classCallCheck(this, GeoJSONLayer2);
function GeoJSONLayer(geojson, options) {
_classCallCheck(this, GeoJSONLayer);
var defaults = {
output: false,
@ -16373,12 +15893,12 @@ return /******/ (function(modules) { // webpackBootstrap
_options.style = (0, _lodashAssign2['default'])({}, defaults.style, options.style);
}
_get(Object.getPrototypeOf(GeoJSONLayer2.prototype), 'constructor', this).call(this, _options);
_get(Object.getPrototypeOf(GeoJSONLayer.prototype), 'constructor', this).call(this, _options);
this._geojson = geojson;
}
_createClass(GeoJSONLayer2, [{
_createClass(GeoJSONLayer, [{
key: '_onAdd',
value: function _onAdd(world) {
// Only add to picking mesh if this layer is controlling output
@ -16418,6 +15938,12 @@ return /******/ (function(modules) { // webpackBootstrap
_this._request = null;
});
}
// TODO: Wrap into a helper method so this isn't duplicated in the tiled
// GeoJSON output layer
//
// Need to be careful as to not make it impossible to fork this off into a
// worker script at a later stage
}, {
key: '_processData',
value: function _processData(data) {
@ -16661,23 +16187,23 @@ return /******/ (function(modules) { // webpackBootstrap
}
// Run common destruction logic from parent
_get(Object.getPrototypeOf(GeoJSONLayer2.prototype), 'destroy', this).call(this);
_get(Object.getPrototypeOf(GeoJSONLayer.prototype), 'destroy', this).call(this);
}
}]);
return GeoJSONLayer2;
return GeoJSONLayer;
})(_LayerGroup3['default']);
exports['default'] = GeoJSONLayer2;
exports['default'] = GeoJSONLayer;
var noNew = function noNew(geojson, options) {
return new GeoJSONLayer2(geojson, options);
return new GeoJSONLayer(geojson, options);
};
exports.geoJSONLayer2 = noNew;
exports.geoJSONLayer = noNew;
/***/ },
/* 77 */
/* 76 */
/***/ function(module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {
@ -16767,7 +16293,7 @@ return /******/ (function(modules) { // webpackBootstrap
exports.layerGroup = noNew;
/***/ },
/* 78 */
/* 77 */
/***/ function(module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {
@ -17366,7 +16892,7 @@ return /******/ (function(modules) { // webpackBootstrap
exports.polygonLayer = noNew;
/***/ },
/* 79 */
/* 78 */
/***/ function(module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {
@ -17782,7 +17308,7 @@ return /******/ (function(modules) { // webpackBootstrap
exports.polylineLayer = noNew;
/***/ },
/* 80 */
/* 79 */
/***/ function(module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -11,17 +11,7 @@ VIZI.Controls.orbit().addTo(world);
// attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, &copy; <a href="http://cartodb.com/attributions">CartoDB</a>'
// }).addTo(world);
// var coordinates = [[[-0.34535,51.54392],[-0.34436,51.54604],[-0.34324,51.54584],[-0.34423,51.54372],[-0.34535,51.54392]]];
//
// VIZI.polygonLayer(coordinates, {
// interactive: true,
// style: {
// color: '#ff0000',
// height: 0
// }
// }).addTo(world);
var layer = VIZI.geoJSONLayer2('http://vector.mapzen.com/osm/buildings,roads/13/4088/2722.json', {
var layer = VIZI.geoJSONLayer('http://vector.mapzen.com/osm/buildings,roads/13/4088/2722.json', {
output: true,
interactive: true,
style: {
@ -36,7 +26,6 @@ var layer = VIZI.geoJSONLayer2('http://vector.mapzen.com/osm/buildings,roads/13/
// // Building and roads from Mapzen (polygons and linestrings)
// var topoJSONTileLayer = VIZI.topoJSONTileLayer('https://vector.mapzen.com/osm/buildings,roads/{z}/{x}/{y}.topojson?api_key=vector-tiles-NT5Emiw', {
// // picking: true,
// style: function(feature) {
// var height;
//
@ -56,9 +45,6 @@ var layer = VIZI.geoJSONLayer2('http://vector.mapzen.com/osm/buildings,roads/13/
// lineRenderOrder: 2
// };
// },
// // onClick: function(feature, point2d, point3d, intersects) {
// // console.log('Clicked:', feature, point2d, point3d, intersects);
// // },
// attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, <a href="http://whosonfirst.mapzen.com#License">Who\'s On First</a>.'
// }).addTo(world);
@ -89,7 +75,7 @@ var layer = VIZI.geoJSONLayer2('http://vector.mapzen.com/osm/buildings,roads/13/
// London Underground lines
// var geoJSONLayer = VIZI.geoJSONLayer('https://rawgit.com/robhawkes/4acb9d6a6a5f00a377e2/raw/30ae704a44e10f2e13fb7e956e80c3b22e8e7e81/tfl_lines.json', {
// picking: true,
// interactive: true,
// style: function(feature) {
// var colour = feature.properties.lines[0].colour || '#ffffff';
//
@ -103,8 +89,10 @@ var layer = VIZI.geoJSONLayer2('http://vector.mapzen.com/osm/buildings,roads/13/
// lineRenderOrder: 2
// };
// },
// onClick: function(feature, point2d, point3d, intersects) {
// console.log('Clicked:', feature, point2d, point3d, intersects);
// onEachFeature: function(feature, layer) {
// layer.on('click', function(layer, point2d, point3d, intersects) {
// console.log(layer, point2d, point3d, intersects);
// });
// },
// attribution: '&copy; Transport for London.'
// }).addTo(world);

Wyświetl plik

@ -1,42 +1,45 @@
import Layer from './Layer';
import THREE from 'three';
import reqwest from 'reqwest';
import LayerGroup from './LayerGroup';
import extend from 'lodash.assign';
import {point as Point} from '../geo/Point';
import {latLon as LatLon} from '../geo/LatLon';
import reqwest from 'reqwest';
import GeoJSON from '../util/GeoJSON';
import Buffer from '../util/Buffer';
import PickingMaterial from '../engine/PickingMaterial';
import PolygonLayer from './geometry/PolygonLayer';
import PolylineLayer from './geometry/PolylineLayer';
class GeoJSONLayer extends Layer {
class GeoJSONLayer extends LayerGroup {
constructor(geojson, options) {
var defaults = {
picking: false,
output: false,
interactive: false,
topojson: false,
filter: null,
onClick: null,
onEachFeature: null,
style: GeoJSON.defaultStyle
};
var _options = extend({}, defaults, options);
super(_options);
if (typeof options.style === 'function') {
this._options.style = options.style;
_options.style = options.style;
} else {
this._options.style = extend({}, defaults.style, options.style);
_options.style = extend({}, defaults.style, options.style);
}
this._defaultStyle = GeoJSON.defaultStyle;
super(_options);
this._geojson = geojson;
this._pickingMesh = new THREE.Object3D();
}
_onAdd(world) {
this.addToPicking(this._pickingMesh);
// Only add to picking mesh if this layer is controlling output
//
// Otherwise, assume another component will eventually add a mesh to
// the picking scene
if (this.isOutput()) {
this._pickingMesh = new THREE.Object3D();
this.addToPicking(this._pickingMesh);
}
// Request data from URL if needed
if (typeof this._geojson === 'string') {
@ -64,9 +67,15 @@ class GeoJSONLayer extends Layer {
});
}
// TODO: Wrap into a helper method so this isn't duplicated in the tiled
// GeoJSON output layer
//
// Need to be careful as to not make it impossible to fork this off into a
// worker script at a later stage
_processData(data) {
console.time('GeoJSON');
// Collects features into a single FeatureCollection
//
// Also converts TopoJSON to GeoJSON if instructed
var geojson = GeoJSON.collectFeatures(data, this._options.topojson);
// TODO: Check that GeoJSON is valid / usable
@ -78,313 +87,198 @@ class GeoJSONLayer extends Layer {
features = geojson.features.filter(this._options.filter);
}
var defaults = {};
// Assume that a style won't be set per feature
var style = this._options.style;
var offset;
// TODO: Wrap into a helper method so this isn't duplicated in the tiled
// GeoJSON output layer
//
// Need to be careful as to not make it impossible to fork this off into a
// worker script at a later stage
//
// Also unsure as to whether it's wise to lump so much into a black box
//
// var meshes = GeoJSON.createMeshes(features, offset, style);
var polygons = {
vertices: [],
faces: [],
colours: [],
facesCount: 0,
allFlat: true
};
var lines = {
vertices: [],
colours: [],
verticesCount: 0
};
if (this._options.picking) {
polygons.pickingIds = [];
lines.pickingIds = [];
}
var colour = new THREE.Color();
var options;
features.forEach(feature => {
// feature.geometry, feature.properties
// Get per-feature style object, if provided
if (typeof this._options.style === 'function') {
style = extend(GeoJSON.defaultStyle, this._options.style(feature));
}
// Skip features that aren't supported
//
// TODO: Add support for all GeoJSON geometry types, including Multi...
// geometry types
if (
feature.geometry.type !== 'Polygon' &&
feature.geometry.type !== 'LineString' &&
feature.geometry.type !== 'MultiLineString'
) {
options = extend({}, defaults, {
// If merging feature layers, stop them outputting themselves
// If not, let feature layers output themselves to the world
output: !this.isOutput(),
interactive: this._options.interactive,
style: style
});
var layer = this._featureToLayer(feature, options);
if (!layer) {
return;
}
// Get style object, if provided
if (typeof this._options.style === 'function') {
style = extend(this._defaultStyle, this._options.style(feature));
layer.feature = feature;
// If defined, call a function for each feature
//
// This is commonly used for adding event listeners from the user script
if (this._options.onEachFeature) {
this._options.onEachFeature(feature, layer);
}
var coordinates = feature.geometry.coordinates;
this.addLayer(layer);
});
// if (feature.geometry.type === 'LineString') {
if (feature.geometry.type === 'LineString') {
colour.set(style.lineColor);
// If merging layers do that now, otherwise skip as the geometry layers
// should have already outputted themselves
if (!this.isOutput()) {
return;
}
coordinates = coordinates.map(coordinate => {
var latlon = LatLon(coordinate[1], coordinate[0]);
var point = this._world.latLonToPoint(latlon);
// From here on we can assume that we want to merge the layers
if (!offset) {
offset = Point(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
var polygonAttributes = [];
var polygonFlat = true;
this._pointScale = this._world.pointScale(latlon);
}
var polylineAttributes = [];
return [point.x, point.y];
});
this._layers.forEach(layer => {
if (layer instanceof PolygonLayer) {
polygonAttributes.push(layer.getBufferAttributes());
var height = 0;
if (style.lineHeight) {
height = this._world.metresToWorld(style.lineHeight, this._pointScale);
if (polygonFlat && !layer.isFlat()) {
polygonFlat = false;
}
var linestringAttributes = GeoJSON.lineStringAttributes(coordinates, colour, height);
lines.vertices.push(linestringAttributes.vertices);
lines.colours.push(linestringAttributes.colours);
if (this._options.picking) {
var pickingId = this.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
lines.pickingIds.push(pickingId);
if (this._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
this._world.on('pick-' + pickingId, (point2d, point3d, intersects) => {
this._options.onClick(feature, point2d, point3d, intersects);
});
}
}
lines.verticesCount += linestringAttributes.vertices.length;
}
if (feature.geometry.type === 'MultiLineString') {
colour.set(style.lineColor);
coordinates = coordinates.map(_coordinates => {
return _coordinates.map(coordinate => {
var latlon = LatLon(coordinate[1], coordinate[0]);
var point = this._world.latLonToPoint(latlon);
if (!offset) {
offset = Point(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
this._pointScale = this._world.pointScale(latlon);
}
return [point.x, point.y];
});
});
var height = 0;
if (style.lineHeight) {
height = this._world.metresToWorld(style.lineHeight, this._pointScale);
}
var multiLinestringAttributes = GeoJSON.multiLineStringAttributes(coordinates, colour, height);
lines.vertices.push(multiLinestringAttributes.vertices);
lines.colours.push(multiLinestringAttributes.colours);
if (this._options.picking) {
var pickingId = this.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
lines.pickingIds.push(pickingId);
if (this._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
this._world.on('pick-' + pickingId, (point2d, point3d, intersects) => {
this._options.onClick(feature, point2d, point3d, intersects);
});
}
}
lines.verticesCount += multiLinestringAttributes.vertices.length;
}
if (feature.geometry.type === 'Polygon') {
colour.set(style.color);
coordinates = coordinates.map(ring => {
return ring.map(coordinate => {
var latlon = LatLon(coordinate[1], coordinate[0]);
var point = this._world.latLonToPoint(latlon);
if (!offset) {
offset = Point(0, 0);
offset.x = -1 * point.x;
offset.y = -1 * point.y;
this._pointScale = this._world.pointScale(latlon);
}
return [point.x, point.y];
});
});
var height = 0;
if (style.height) {
height = this._world.metresToWorld(style.height, this._pointScale);
}
var polygonAttributes = GeoJSON.polygonAttributes(coordinates, colour, height);
polygons.vertices.push(polygonAttributes.vertices);
polygons.faces.push(polygonAttributes.faces);
polygons.colours.push(polygonAttributes.colours);
if (this._options.picking) {
var pickingId = this.getPickingId();
// Inject picking ID
//
// TODO: Perhaps handle this within the GeoJSON helper
polygons.pickingIds.push(pickingId);
if (this._options.onClick) {
// TODO: Find a way to properly remove this listener on destroy
this._world.on('pick-' + pickingId, (point2d, point3d, intersects) => {
this._options.onClick(feature, point2d, point3d, intersects);
});
}
}
if (polygons.allFlat && !polygonAttributes.flat) {
polygons.allFlat = false;
}
polygons.facesCount += polygonAttributes.faces.length;
} else if (layer instanceof PolylineLayer) {
polylineAttributes.push(layer.getBufferAttributes());
}
});
var geometry;
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
this._setPolygonMesh(mergedPolygonAttributes, polygonFlat);
this.add(this._polygonMesh);
this._setPolylineMesh(mergedPolylineAttributes);
this.add(this._polylineMesh);
}
// Create and store mesh from buffer attributes
//
// TODO: De-dupe this from the individual mesh creation logic within each
// geometry layer (materials, settings, etc)
_setPolygonMesh(attributes, flat) {
var geometry = new THREE.BufferGeometry();
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('normal', new THREE.BufferAttribute(attributes.normals, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
if (attributes.pickingIds) {
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
}
geometry.computeBoundingBox();
var material;
var mesh;
if (this._options.picking) {
// Move picking mesh to origin Point
this._pickingMesh.position.x = -offset.x;
this._pickingMesh.position.z = -offset.y;
}
// Output lines
if (lines.vertices.length > 0) {
geometry = Buffer.createLineGeometry(lines, offset);
material = new THREE.LineBasicMaterial({
if (!this._world._environment._skybox) {
material = new THREE.MeshPhongMaterial({
vertexColors: THREE.VertexColors,
linewidth: style.lineWidth,
transparent: style.lineTransparent,
opacity: style.lineOpacity,
blending: style.lineBlending
side: THREE.BackSide
});
mesh = new THREE.LineSegments(geometry, material);
if (style.lineRenderOrder !== undefined) {
material.depthWrite = false;
mesh.renderOrder = style.lineRenderOrder;
}
// TODO: Can a line cast a shadow?
// mesh.castShadow = true;
this.add(mesh);
if (this._options.picking) {
material = new PickingMaterial();
material.side = THREE.BackSide;
// Make the line wider / easier to pick
material.linewidth = style.lineWidth + material.linePadding;
var pickingMesh = new THREE.LineSegments(geometry, material);
this._pickingMesh.add(pickingMesh);
}
} else {
material = new THREE.MeshStandardMaterial({
vertexColors: THREE.VertexColors,
side: THREE.BackSide
});
material.roughness = 1;
material.metalness = 0.1;
material.envMapIntensity = 3;
material.envMap = this._world._environment._skybox.getRenderTarget();
}
// Output polygons
if (polygons.facesCount > 0) {
geometry = Buffer.createGeometry(polygons, offset);
mesh = new THREE.Mesh(geometry, material);
if (!this._world._environment._skybox) {
material = new THREE.MeshPhongMaterial({
vertexColors: THREE.VertexColors,
side: THREE.BackSide
});
} else {
material = new THREE.MeshStandardMaterial({
vertexColors: THREE.VertexColors,
side: THREE.BackSide
});
material.roughness = 1;
material.metalness = 0.1;
material.envMapIntensity = 3;
material.envMap = this._world._environment._skybox.getRenderTarget();
}
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
if (polygons.allFlat) {
material.depthWrite = false;
mesh.renderOrder = 1;
}
this.add(mesh);
if (this._options.picking) {
material = new PickingMaterial();
material.side = THREE.BackSide;
var pickingMesh = new THREE.Mesh(geometry, material);
this._pickingMesh.add(pickingMesh);
}
if (flat) {
material.depthWrite = false;
mesh.renderOrder = 1;
}
// Move layer to origin Point
//
// TODO: Is there a better way to ensure everything is aligned right and
// able to be frustum-culled?
this._object3D.position.x = -offset.x;
this._object3D.position.z = -offset.y;
if (this._options.interactive && this._pickingMesh) {
material = new PickingMaterial();
material.side = THREE.BackSide;
console.timeEnd('GeoJSON');
var pickingMesh = new THREE.Mesh(geometry, material);
this._pickingMesh.add(pickingMesh);
}
this._polygonMesh = mesh;
}
_setPolylineMesh(attributes) {
var geometry = new THREE.BufferGeometry();
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
if (attributes.pickingIds) {
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
}
geometry.computeBoundingBox();
// TODO: Make this work when style is a function per feature
var style = this._options.style;
var material = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors,
linewidth: style.lineWidth,
transparent: style.lineTransparent,
opacity: style.lineOpacity,
blending: style.lineBlending
});
var mesh = new THREE.LineSegments(geometry, material);
if (style.lineRenderOrder !== undefined) {
material.depthWrite = false;
mesh.renderOrder = style.lineRenderOrder;
}
// TODO: Can a line cast a shadow?
// mesh.castShadow = true;
if (this._options.interactive && this._pickingMesh) {
material = new PickingMaterial();
material.side = THREE.BackSide;
// Make the line wider / easier to pick
material.linewidth = style.lineWidth + material.linePadding;
var pickingMesh = new THREE.LineSegments(geometry, material);
this._pickingMesh.add(pickingMesh);
}
this._polylineMesh = mesh;
}
// TODO: Support all GeoJSON geometry types
_featureToLayer(feature, options) {
var geometry = feature.geometry;
var coordinates = (geometry.coordinates) ? geometry.coordinates : null;
if (!coordinates || !geometry) {
return;
}
if (geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
return new PolygonLayer(coordinates, options);
}
if (geometry.type === 'LineString' || geometry.type === 'MultiLineString') {
return new PolylineLayer(coordinates, options);
}
}
_abortRequest() {
@ -395,6 +289,7 @@ class GeoJSONLayer extends Layer {
this._request.abort();
}
// Destroy the layers and remove them from the scene and memory
destroy() {
// Cancel any pending requests
this._abortRequest();
@ -402,8 +297,10 @@ class GeoJSONLayer extends Layer {
// Clear request reference
this._request = null;
// TODO: Properly dispose of picking mesh
this._pickingMesh = null;
if (this._pickingMesh) {
// TODO: Properly dispose of picking mesh
this._pickingMesh = null;
}
// Run common destruction logic from parent
super.destroy();
@ -416,5 +313,4 @@ var noNew = function(geojson, options) {
return new GeoJSONLayer(geojson, options);
};
// Initialise without requiring new keyword
export {noNew as geoJSONLayer};

Wyświetl plik

@ -1,311 +0,0 @@
import LayerGroup from './LayerGroup';
import extend from 'lodash.assign';
import reqwest from 'reqwest';
import GeoJSON from '../util/GeoJSON';
import Buffer from '../util/Buffer';
import PickingMaterial from '../engine/PickingMaterial';
import PolygonLayer from './geometry/PolygonLayer';
import PolylineLayer from './geometry/PolylineLayer';
class GeoJSONLayer2 extends LayerGroup {
constructor(geojson, options) {
var defaults = {
output: false,
interactive: false,
topojson: false,
filter: null,
onEachFeature: null,
style: GeoJSON.defaultStyle
};
var _options = extend({}, defaults, options);
if (typeof options.style === 'function') {
_options.style = options.style;
} else {
_options.style = extend({}, defaults.style, options.style);
}
super(_options);
this._geojson = geojson;
}
_onAdd(world) {
// Only add to picking mesh if this layer is controlling output
//
// Otherwise, assume another component will eventually add a mesh to
// the picking scene
if (this.isOutput()) {
this._pickingMesh = new THREE.Object3D();
this.addToPicking(this._pickingMesh);
}
// Request data from URL if needed
if (typeof this._geojson === 'string') {
this._requestData(this._geojson);
} else {
// Process and add GeoJSON to layer
this._processData(this._geojson);
}
}
_requestData(url) {
this._request = reqwest({
url: url,
type: 'json',
crossOrigin: true
}).then(res => {
// Clear request reference
this._request = null;
this._processData(res);
}).catch(err => {
console.error(err);
// Clear request reference
this._request = null;
});
}
_processData(data) {
// Collects features into a single FeatureCollection
//
// Also converts TopoJSON to GeoJSON if instructed
var geojson = GeoJSON.collectFeatures(data, this._options.topojson);
// TODO: Check that GeoJSON is valid / usable
var features = geojson.features;
// Run filter, if provided
if (this._options.filter) {
features = geojson.features.filter(this._options.filter);
}
var defaults = {};
// Assume that a style won't be set per feature
var style = this._options.style;
var options;
features.forEach(feature => {
// Get per-feature style object, if provided
if (typeof this._options.style === 'function') {
style = extend(GeoJSON.defaultStyle, this._options.style(feature));
}
options = extend({}, defaults, {
// If merging feature layers, stop them outputting themselves
// If not, let feature layers output themselves to the world
output: !this.isOutput(),
interactive: this._options.interactive,
style: style
});
var layer = this._featureToLayer(feature, options);
if (!layer) {
return;
}
layer.feature = feature;
// If defined, call a function for each feature
//
// This is commonly used for adding event listeners from the user script
if (this._options.onEachFeature) {
this._options.onEachFeature(feature, layer);
}
this.addLayer(layer);
});
// If merging layers do that now, otherwise skip as the geometry layers
// should have already outputted themselves
if (!this.isOutput()) {
return;
}
// From here on we can assume that we want to merge the layers
var polygonAttributes = [];
var polygonFlat = true;
var polylineAttributes = [];
this._layers.forEach(layer => {
if (layer instanceof PolygonLayer) {
polygonAttributes.push(layer.getBufferAttributes());
if (polygonFlat && !layer.isFlat()) {
polygonFlat = false;
}
} else if (layer instanceof PolylineLayer) {
polylineAttributes.push(layer.getBufferAttributes());
}
});
var mergedPolygonAttributes = Buffer.mergeAttributes(polygonAttributes);
var mergedPolylineAttributes = Buffer.mergeAttributes(polylineAttributes);
this._setPolygonMesh(mergedPolygonAttributes, polygonFlat);
this.add(this._polygonMesh);
this._setPolylineMesh(mergedPolylineAttributes);
this.add(this._polylineMesh);
}
// Create and store mesh from buffer attributes
//
// TODO: De-dupe this from the individual mesh creation logic within each
// geometry layer (materials, settings, etc)
_setPolygonMesh(attributes, flat) {
var geometry = new THREE.BufferGeometry();
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('normal', new THREE.BufferAttribute(attributes.normals, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
if (attributes.pickingIds) {
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
}
geometry.computeBoundingBox();
var material;
if (!this._world._environment._skybox) {
material = new THREE.MeshPhongMaterial({
vertexColors: THREE.VertexColors,
side: THREE.BackSide
});
} else {
material = new THREE.MeshStandardMaterial({
vertexColors: THREE.VertexColors,
side: THREE.BackSide
});
material.roughness = 1;
material.metalness = 0.1;
material.envMapIntensity = 3;
material.envMap = this._world._environment._skybox.getRenderTarget();
}
mesh = new THREE.Mesh(geometry, material);
mesh.castShadow = true;
mesh.receiveShadow = true;
if (flat) {
material.depthWrite = false;
mesh.renderOrder = 1;
}
if (this._options.interactive && this._pickingMesh) {
material = new PickingMaterial();
material.side = THREE.BackSide;
var pickingMesh = new THREE.Mesh(geometry, material);
this._pickingMesh.add(pickingMesh);
}
this._polygonMesh = mesh;
}
_setPolylineMesh(attributes) {
var geometry = new THREE.BufferGeometry();
// itemSize = 3 because there are 3 values (components) per vertex
geometry.addAttribute('position', new THREE.BufferAttribute(attributes.vertices, 3));
geometry.addAttribute('color', new THREE.BufferAttribute(attributes.colours, 3));
if (attributes.pickingIds) {
geometry.addAttribute('pickingId', new THREE.BufferAttribute(attributes.pickingIds, 1));
}
geometry.computeBoundingBox();
// TODO: Make this work when style is a function per feature
var style = this._options.style;
var material = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors,
linewidth: style.lineWidth,
transparent: style.lineTransparent,
opacity: style.lineOpacity,
blending: style.lineBlending
});
var mesh = new THREE.LineSegments(geometry, material);
if (style.lineRenderOrder !== undefined) {
material.depthWrite = false;
mesh.renderOrder = style.lineRenderOrder;
}
// TODO: Can a line cast a shadow?
// mesh.castShadow = true;
if (this._options.interactive && this._pickingMesh) {
material = new PickingMaterial();
material.side = THREE.BackSide;
// Make the line wider / easier to pick
material.linewidth = style.lineWidth + material.linePadding;
var pickingMesh = new THREE.LineSegments(geometry, material);
this._pickingMesh.add(pickingMesh);
}
this._polylineMesh = mesh;
}
// TODO: Support all GeoJSON geometry types
_featureToLayer(feature, options) {
var geometry = feature.geometry;
var coordinates = (geometry.coordinates) ? geometry.coordinates : null;
if (!coordinates || !geometry) {
return;
}
if (geometry.type === 'Polygon' || geometry.type === 'MultiPolygon') {
return new PolygonLayer(coordinates, options);
}
if (geometry.type === 'LineString' || geometry.type === 'MultiLineString') {
return new PolylineLayer(coordinates, options);
}
}
_abortRequest() {
if (!this._request) {
return;
}
this._request.abort();
}
// Destroy the layers and remove them from the scene and memory
destroy() {
// Cancel any pending requests
this._abortRequest();
// Clear request reference
this._request = null;
if (this._pickingMesh) {
// TODO: Properly dispose of picking mesh
this._pickingMesh = null;
}
// Run common destruction logic from parent
super.destroy();
}
}
export default GeoJSONLayer2;
var noNew = function(geojson, options) {
return new GeoJSONLayer2(geojson, options);
};
export {noNew as geoJSONLayer2};

Wyświetl plik

@ -7,7 +7,6 @@ import ImageTileLayer, {imageTileLayer} from './layer/tile/ImageTileLayer';
import GeoJSONTileLayer, {geoJSONTileLayer} from './layer/tile/GeoJSONTileLayer';
import TopoJSONTileLayer, {topoJSONTileLayer} from './layer/tile/TopoJSONTileLayer';
import GeoJSONLayer, {geoJSONLayer} from './layer/GeoJSONLayer';
import GeoJSONLayer2, {geoJSONLayer2} from './layer/GeoJSONLayer2';
import TopoJSONLayer, {topoJSONLayer} from './layer/TopoJSONLayer';
import PolygonLayer, {polygonLayer} from './layer/geometry/PolygonLayer';
import PolylineLayer, {polylineLayer} from './layer/geometry/PolylineLayer';
@ -34,8 +33,6 @@ const VIZI = {
topoJSONTileLayer: topoJSONTileLayer,
GeoJSONLayer: GeoJSONLayer,
geoJSONLayer: geoJSONLayer,
GeoJSONLayer2: GeoJSONLayer2,
geoJSONLayer2: geoJSONLayer2,
TopoJSONLayer: TopoJSONLayer,
topoJSONLayer: topoJSONLayer,
PolygonLayer: PolygonLayer,