Skip to content

Commit

Permalink
feat(example): add a DragNDrop module in examples/
Browse files Browse the repository at this point in the history
This module can be added to a web page using the `<script>` tag or used
as a module in a built webapp. The user can then bind the viewer to it,
and register some file extensions to support. It is very simple, but can
be used for quick examples where people want to test files without
having to write code.
  • Loading branch information
zarov committed Jun 12, 2019
1 parent 10e4df1 commit 1fcca5a
Show file tree
Hide file tree
Showing 7 changed files with 285 additions and 4 deletions.
6 changes: 5 additions & 1 deletion docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@
"$3DTilesExtensions",
"$3dTilesAbstractExtension",
"BatchTableHierarchyExtension"
],

"Plugins": [
"DragNDrop"
]
}
},
Expand All @@ -102,7 +106,7 @@
}
},
"source": {
"include": [ "src" ],
"include": [ "src", "examples/js" ],
"exclude": [ "src/ThreeExtended" ]
},
"plugins": ["plugins/markdown"]
Expand Down
4 changes: 2 additions & 2 deletions docs/publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
3 changes: 2 additions & 1 deletion examples/css/example.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 62 additions & 0 deletions examples/drag-n-drop.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<html>
<head>
<title>Itowns - GeoJSON drag and drop</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="css/example.css">
<link rel="stylesheet" type="text/css" href="css/loading_screen.css">

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="js/GUI/dat.gui/dat.gui.min.js"></script>
</head>
<body>
<div id="viewerDiv">
<div class="help"><p>Drag and drop a Geojson or Gpx file onto the viewer, and see it
loaded as a ColorLayer.</p></div>
</div>
<script src="js/GUI/GuiTools.js"></script>
<script src="js/DragNDrop.js"></script>
<script src="../dist/itowns.js"></script>
<script src="js/loading_screen.js"></script>
<script src="../dist/debug.js"></script>
<script type="text/javascript">
// Define initial camera position
var positionOnGlobe = { longitude: 2.351323, latitude: 48.856712,
altitude: 250000 };

// `viewerDiv` will contain iTowns' rendering area (`<canvas>`)
var viewerDiv = document.getElementById('viewerDiv');

// Instanciate iTowns GlobeView*
var view = new itowns.GlobeView(viewerDiv, positionOnGlobe);
setupLoadingScreen(viewerDiv, view);

// Add one imagery layer to the scene
// This layer is defined in a json file but it could be defined as a plain js
// object. See Layer* for more info.
itowns.Fetcher.json('./layers/JSONLayers/Ortho.json').then(function _(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ColorLayer('Ortho', config);
view.addLayer(layer).then(menuGlobe.addLayerGUI.bind(menuGlobe));
});

// Add two elevation layers.
// These will deform iTowns globe geometry to represent terrain elevation.
function addElevationLayerFromConfig(config) {
config.source = new itowns.WMTSSource(config.source);
var layer = new itowns.ElevationLayer(config.id, config);
view.addLayer(layer);
}
itowns.Fetcher.json('./layers/JSONLayers/WORLD_DTM.json').then(addElevationLayerFromConfig);
itowns.Fetcher.json('./layers/JSONLayers/IGN_MNT_HIGHRES.json').then(addElevationLayerFromConfig);

DragNDrop.setView(view);
DragNDrop.register('geojson', DragNDrop.JSON, itowns.GeoJsonParser.parse, DragNDrop.COLOR);
DragNDrop.register('gpx', DragNDrop.XML, itowns.GpxParser.parse, DragNDrop.COLOR);

var menuGlobe = new GuiTools('menuDiv', view);
var d = new debug.Debug(view, menuGlobe.gui);
debug.createTileDebugUI(menuGlobe.gui, view, view.tileLayer, d);
</script>
</body>
</html>

6 changes: 6 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -212,5 +212,11 @@ <h3>Displaying shapefile as a color layer</h3>
<img src='screenshots/shapefile.jpg'>
</a>
</div>
<div class="exampleContainer">
<a href='./drag-n-drop.html' target='_blank'>
<h3>Drop a geojson or a gpx file and display it as a ColorLayer</h3>
<img src='screenshots/drag-n-drop.jpg'>
</a>
</div>
</body>
</html>
208 changes: 208 additions & 0 deletions examples/js/DragNDrop.js
Original file line number Diff line number Diff line change
@@ -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
* &lt;script src="js/DragNDrop.js">&lt;/script>
* &lt;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);
* &lt;/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;
}
Binary file added examples/screenshots/drag-n-drop.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1fcca5a

Please sign in to comment.