diff --git a/docs/config.json b/docs/config.json index f0d743eb13..040b1decc8 100644 --- a/docs/config.json +++ b/docs/config.json @@ -91,6 +91,10 @@ "$3DTilesExtensions", "$3dTilesAbstractExtension", "BatchTableHierarchyExtension" + ], + + "Plugins": [ + "DragNDrop" ] } }, @@ -102,7 +106,7 @@ } }, "source": { - "include": [ "src" ], + "include": [ "src", "examples/js" ], "exclude": [ "src/ThreeExtended" ] }, "plugins": ["plugins/markdown"] diff --git a/docs/publish.js b/docs/publish.js index d65de394a9..14c3f644c0 100644 --- a/docs/publish.js +++ b/docs/publish.js @@ -23,8 +23,8 @@ function find(spec) { } function linkToSource(filename, path) { - const location = path.split('src')[1]; - return `src${location}/${filename}`; + const location = path.split('itowns/')[1]; + return `${location}/${filename}`; } function rank(properties) { diff --git a/examples/css/example.css b/examples/css/example.css index 5099dd7321..4c12d0eaff 100644 --- a/examples/css/example.css +++ b/examples/css/example.css @@ -37,7 +37,8 @@ body { top: 0; right: 0; color: #eee; - font: 11px 'Lucida Grande',sans-serif; + font: 16px 'Lucida Grande',sans-serif; + max-width: 20rem; line-height: normal; text-shadow: 0 -1px 0 #111; padding: 0 1rem; diff --git a/examples/drag-n-drop.html b/examples/drag-n-drop.html new file mode 100644 index 0000000000..930082893c --- /dev/null +++ b/examples/drag-n-drop.html @@ -0,0 +1,62 @@ + + + Itowns - GeoJSON drag and drop + + + + + + + + +
+

Drag and drop a Geojson or Gpx file onto the viewer, and see it + loaded as a ColorLayer.

+
+ + + + + + + + + diff --git a/examples/index.html b/examples/index.html index c0f005cc9b..8c934fc6ef 100644 --- a/examples/index.html +++ b/examples/index.html @@ -212,5 +212,11 @@

Displaying shapefile as a color layer

+
+ +

Drop a geojson or a gpx file and display it as a ColorLayer

+ +
+
diff --git a/examples/js/DragNDrop.js b/examples/js/DragNDrop.js new file mode 100644 index 0000000000..68c2bc5a1d --- /dev/null +++ b/examples/js/DragNDrop.js @@ -0,0 +1,208 @@ +/* global itowns */ +/** + * This module can be added to a web page or in a web application. It provides a + * simple behavior where single files can be drag and dropped onto a viewer. No + * relationship between a type of file and the way it is read, parsed and + * displayed are stored in the plugin. Use the method `register` to declare the + * way a file is read, parsed and displayed. + * + * Note: only files with the projection `EPSG:4326` can be projected correctly + * using this plugin. + * + * @module DragNDrop + * + * @example + * <script src="js/DragNDrop.js"></script> + * <script type="text/javascript"> + * var view = new itowns.GlobeView(document.getElementById('viewerDiv')); + * + * DragNDrop.setView(view); + * DragNDrop.register('geojson', DragNDrop.JSON, itowns.GeoJsonParser.parse, DragNDrop.COLOR); + * DragNDrop.register('gpx', DragNDrop.XML, itowns.GpxParser.parse, DragNDrop.GEOMETRY); + * </script> + * + * @example + * require('./js/itowns.js'); + * require('./plugins/DragNDrop.js'); + * + * const view = new itowns.GlobeView(document.getElementById('viewerDiv')); + * + * DragNDrop.setView(view); + * DragNDrop.register('geojson', DragNDrop.JSON, itowns.GeoJsonParser.parse, DragNDrop.COLOR); + * DragNDrop.register('gpx', DragNDrop.XML, itowns.GpxParser.parse, DragNDrop.GEOMETRY); + */ +var DragNDrop = (function _() { + // TYPE + var _TEXT = 1; + var _JSON = 2; + var _BINARY = 3; + var _IMAGE = 4; + var _XML = 5; + + // MODE + var _COLOR = 6; + var _GEOMETRY = 7; + + var extensionsMap = {}; + var fileReader = new FileReader(); + + var _view; + + function addFiles(event, files) { + event.preventDefault(); + + // Read each file + for (var i = 0; i < files.length; i++) { + var file = files[i]; + var extension = extensionsMap[file.name.split('.').pop().toLowerCase()]; + + // eslint-disable-next-line no-loop-func + fileReader.onload = function onload(e) { + var data = e.target.result; + + if (extension.type == _JSON) { + data = JSON.parse(data); + } else if (extension.type == _XML) { + data = new window.DOMParser().parseFromString(data, 'text/xml'); + } + + extension.parser(data, { + buildExtent: true, + crsIn: 'EPSG:4326', + crsOut: (extension.mode == _GEOMETRY ? _view.referenceCrs : _view.tileLayer.extent.crs), + mergeFeatures: true, + withNormal: (extension.mode == _GEOMETRY), + withAltitude: (extension.mode == _GEOMETRY), + }).then(function _(result) { + var dimensions = result.extent.dimensions(); + + var source = new itowns.FileSource({ + parsedData: result, + projection: 'EPSG:4326', + }); + + var randomColor = Math.round(Math.random() * 0xffffff); + + var layer; + if (extension.mode == _COLOR) { + layer = new itowns.ColorLayer(file.name, { + transparent: true, + style: { + fill: { + color: '#' + randomColor.toString(16), + opacity: 0.7, + }, + stroke: { + color: '#' + randomColor.toString(16), + }, + }, + source: source, + }); + } else if (extension.mode == _GEOMETRY) { + layer = new itowns.GeometryLayer(file.name, new itowns.THREE.Group(), { + update: itowns.FeatureProcessing.update, + convert: itowns.Feature2Mesh.convert({ + color: new itowns.THREE.Color(randomColor), + // Set the extrusion according to the size of + // the extent containing the data; this quick + // formula is totally arbitrary. + extrude: dimensions.x * dimensions.y / 1e6, + }), + source: source, + opacity: 0.7, + }); + } else { + throw new Error('Mode of file not supported, please add it using DragNDrop.register'); + } + + _view.addLayer(layer); + + // Move the camera to the first vertex + itowns.CameraUtils.animateCameraToLookAtTarget(_view, _view.camera.camera3D, { + coord: new itowns.Coordinates(result.crs, result.features[0].vertices), + range: dimensions.x * dimensions.y * 1e6, + }); + }); + }; + + switch (extension.type) { + case _TEXT: + case _JSON: + case _XML: + fileReader.readAsText(file); + break; + case _BINARY: + fileReader.readAsArrayBuffer(file); + break; + case _IMAGE: + fileReader.readAsBinaryString(file); + break; + default: + throw new Error('Type of file not supported, please add it using DragNDrop.register'); + } + } + } + + // Listen to drag and drop actions + document.addEventListener('dragenter', function _(e) { e.preventDefault(); }, false); + document.addEventListener('dragover', function _(e) { e.preventDefault(); }, false); + document.addEventListener('dragleave', function _(e) { e.preventDefault(); }, false); + document.addEventListener('drop', function _(e) { addFiles(e, e.dataTransfer.files); }, false); + document.addEventListener('paste', function _(e) { addFiles(e, e.clipboardData.files); }, false); + + return { + TEXT: _TEXT, + JSON: _JSON, + BINARY: _BINARY, + IMAGE: _IMAGE, + XML: _XML, + + COLOR: _COLOR, + GEOMETRY: _GEOMETRY, + + /** + * Register a type of file to read after a drag and drop on the viewer. + * The file will be processed following its extension and instructions + * given here. + * + * @param {string} extension - The extension to register. Each file + * dropped ending with this extension will follow the instructions given + * by the others parameters of this function. + * @param {number} type - The type of file to register. Can be + * `DragNDrop.TEXT` (equivalent to `Fetcher.text`), `DragNDrop.JSON` + * (equivalent to `Fetcher.json`), `DragNDrop.BINARY` (equivalent to + * `Fetcher.arrayBuffer`), `DragNDrop.IMAGE` (equivalent to + * `Fetcher.texture`) or `DragNDrop.XML` (equivalent to `Fetcher.xml`). + * @param {Function} parser - The method to parse the content of the + * added file. + * @param {number} mode - Choose the mode the file is displayed: either + * `DragNDrop.COLOR` (equivalent to a `ColorLayer`) or + * `DragNDrop.GEOMETRY` (equivalent to a `GeometryLayer`). + * + * @memberof module:DragNDrop + */ + register: function _(extension, type, parser, mode) { + extensionsMap[extension.toLowerCase()] = { + type: type, + parser: parser, + mode: mode, + }; + }, + + /** + * The DragNDrop plugin needs to be binded to a view. Specified it using + * this method. + * + * @param {View} view - The view to bind to the DragNDrop interface. + * + * @memberof module:DragNDrop + */ + setView: function _(view) { + _view = view; + }, + }; +}()); + +if (typeof module != 'undefined' && module.exports) { + module.exports = DragNDrop; +} diff --git a/examples/screenshots/drag-n-drop.jpg b/examples/screenshots/drag-n-drop.jpg new file mode 100644 index 0000000000..95a47d629b Binary files /dev/null and b/examples/screenshots/drag-n-drop.jpg differ