-
Notifications
You must be signed in to change notification settings - Fork 451
/
Drag and drop spatial files onto map.html
451 lines (365 loc) · 15.8 KB
/
Drag and drop spatial files onto map.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
<!DOCTYPE html>
<html lang="en">
<head>
<title>Drag and drop spatial files onto map - Azure Maps Web SDK Samples</title>
<meta charset="utf-8" />
<link rel="shortcut icon" href="/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="Drag and drop one or more KML, KMZ, GeoRSS, GPX, GML, GeoJSON or CSV files onto the map." />
<meta name="keywords" content="Microsoft maps, map, gis, API, SDK, KML, KMZ, GeoRSS, GPX, GML, GeoJSON, CSV, ogc, spatial data, spatial io module, geoxml" />
<meta name="author" content="Microsoft Azure Maps" /><meta name="version" content="1.0" />
<meta name="screenshot" content="screenshot.jpg" />
<!-- Add references to the Azure Maps Map control JavaScript and CSS files. -->
<link href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3/atlas.min.css" rel="stylesheet" />
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/3/atlas.min.js"></script>
<!-- Add reference to the Azure Maps Spatial IO module. -->
<script src="https://atlas.microsoft.com/sdk/javascript/spatial/0/atlas-spatial.min.js"></script>
<script>
var map, datasource, imageLayers = [], layer, dataBounds, statusPanel, dataPanel, imageIcons = [], loadingIcon, fileCount = 0;
var proxyServiceUrl = 'https://samples.azuremaps.com/api/GetDataFromUrl?url=';
function getMap() {
statusPanel = document.getElementById('statusPanel');
dataPanel = document.getElementById('dataPanel');
loadingIcon = document.getElementById('loadingIcon');
//Initialize a map instance.
map = new atlas.Map('myMap', {
view: 'Auto',
//Add authentication details for connecting to Azure Maps.
authOptions: {
//Use Microsoft Entra ID authentication.
authType: 'anonymous',
clientId: 'e6b6ab59-eb5d-4d25-aa57-581135b927f0', //Your Azure Maps client id for accessing your Azure Maps account.
getToken: function (resolve, reject, map) {
//URL to your authentication service that retrieves an Microsoft Entra ID Token.
var tokenServiceUrl = 'https://samples.azuremaps.com/api/GetAzureMapsToken';
fetch(tokenServiceUrl).then(r => r.text()).then(token => resolve(token));
}
//Alternatively, use an Azure Maps key. Get an Azure Maps key at https://azure.com/maps. NOTE: The primary key should be used as the key.
//authType: 'subscriptionKey',
//subscriptionKey: '[YOUR_AZURE_MAPS_KEY]'
}
});
//Wait until the map resources are ready.
map.events.add('ready', function () {
//Create a style control and add it to the map.
map.controls.add(new atlas.control.StyleControl({
style: 'dark',
mapStyles: 'all'
}), {
position: 'top-right'
});
//Create a data source to store the data in.
datasource = new atlas.source.DataSource();
map.sources.add(datasource);
//Add a simple data layer for rendering the data.
layer = new atlas.layer.SimpleDataLayer(datasource);
map.layers.add(layer);
//Setup the drag & drop listeners on the map.
var dropZone = document.getElementById('myMap');
dropZone.addEventListener('dragover', handleDragOver, false);
dropZone.addEventListener('drop', handleFileSelect, false);
});
}
function handleDragOver(evt) {
//Stop the browser from performing its default behavior when a file is dragged and dropped.
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
function handleFileSelect(evt) {
statusPanel.value = 'Reading from Files\r\n\r\n';
//Stop the browser from performing its default behavior when a file is dragged and dropped.
evt.stopPropagation();
evt.preventDefault();
clearMap();
//The list of files that have been dragged and dropped onto the map.
var files = evt.dataTransfer.files;
//Loop through and attempt to read each file.
for (var i = 0; i < files.length; i++) {
//Read the data blob.
readData(files[i], files[i].name);
}
}
function readData(data, fileName) {
loadingIcon.style.display = '';
fileCount++;
//Attempt to parse the file and add the shapes to the map.
atlas.io.read(data, {
proxyService: proxyServiceUrl
}).then(
//Success
function (r) {
//Check to see if there is any icon data. If there is, load them into the map before loading the data.
if (r.icons) {
loadIcons(r.icons).then(function () {
loadData(r, fileName);
});
} else {
loadData(r, fileName);
}
},
//Error
function (msg) {
writeStats(fileName, null, msg);
alert(msg);
}
);
}
function readDataPanel() {
statusPanel.value = 'Reading from Data panel\r\n\r\n';
clearMap();
readData(dataPanel.value);
}
function loadData(r, fileName) {
//Load all features.
if (r.features && r.features.length > 0) {
datasource.add(r.features);
}
//Load ground overlays.
if (r.groundOverlays && r.groundOverlays.length > 0) {
imageLayers = imageLayers.concat(r.groundOverlays);
map.layers.add(r.groundOverlays);
}
//If there is a bounding box for the data, set the map to it.
if (r.bbox) {
if (dataBounds) {
//If there are multiple files being loaded, there merge their bounding boxes together.
dataBounds = atlas.data.BoundingBox.merge(dataBounds, r.bbox);
} else {
dataBounds = r.bbox;
}
//Update the map view.
map.setCamera({ bounds: dataBounds, padding: 50 });
}
//Write stats.
writeStats(fileName, r.stats);
}
//Load icons into the map image sprite.
function loadIcons(icons) {
return new Promise(function (resolve, reject) {
if (!icons) {
resolve();
return;
}
//The keys are the names of each icon image.
var keys = Object.keys(icons);
if (keys.length === 0) {
resolve();
return;
}
//For each icon image, create a promise to add it to the map, then run the promises in parrallel.
var imagePromises = [];
keys.forEach(function (key) {
imagePromises.push(map.imageSprite.add(key, icons[key]));
});
Promise.all(imagePromises).then(function () {
//Remember all the added icon names so we can remove them later when the map is cleared.
imageIcons = imageIcons.concat(keys);
resolve();
});
});
}
//Remove any custom loaded icons from the map.
function removeIcons() {
for (var i = 0; i < imageIcons.length; i++) {
map.imageSprite.remove(imageIcons[i]);
}
imageIcons = [];
}
function clearMap() {
//Remove any existing data from the map.
dataBounds = null;
map.layers.remove(imageLayers);
imageLayers = [];
datasource.clear();
removeIcons();
layer.closePopup();
}
//Writes data as a string an adds to data panel.
function writeData() {
dataPanel.value = '';
var fileTypeDD = document.getElementById('fileType');
var fileType = fileTypeDD.options[fileTypeDD.selectedIndex].innerText;
var s = performance.now();
atlas.io.write(imageLayers.concat(datasource.toJson().features), {
format: fileType,
indentChars: ' ' //Use 4 spaces instead of \t for indenting as it looks better in the textarea.
}).then(function (dataString) {
var e = performance.now();
statusPanel.value = 'Data written in: ' + (e - s) + 'ms';
dataPanel.value = dataString;
openTab(null, 'Data');
});
}
//Downloads the data as a compressed file (KMZ or ZIP).
function downloadZip() {
dataPanel.value = '';
var fileTypeDD = document.getElementById('fileType');
var fileType = fileTypeDD.options[fileTypeDD.selectedIndex].innerText;
atlas.io.writeCompressed(imageLayers.concat(datasource.toJson().features), 'Blob', {
format: fileType,
indentChars: ' ' //Use 4 spaces instead of \t for indenting as it looks better in the textarea.
}).then(function (compressedData) {
if (fileType === 'KML') {
saveAs(compressedData, 'MapData.kmz');
} else {
saveAs(compressedData, 'MapData.zip');
}
});
}
//Write reading stats and errors for each file read.
function writeStats(fileName, stats, error) {
var result = [];
if (fileName) {
result.push('File name: ', fileName);
}
if (error) {
result.push('\r\nError: ', error);
}
if (stats) {
if (stats.numCharecters) {
result.push('\r\nFile size: ', Math.ceil(stats.numCharecters / 1024), ' KB');
}
if (stats.numPoints) {
result.push('\r\n# of Points: ', stats.numPoints);
}
if (stats.numLineStrings) {
result.push('\r\n# of LineStrings: ', stats.numLineStrings);
}
if (stats.numPolygons) {
result.push('\r\n# of Polygons: ', stats.numPolygons);
}
if (stats.numPositions) {
result.push('\r\n# of Positions: ', stats.numPositions);
}
if (stats.numNetworkLinks) {
result.push('\r\n# of Network Links: ', stats.numNetworkLinks);
}
if (stats.numGroundOverlays) {
result.push('\r\n# of Ground Overlays ', stats.numGroundOverlays);
}
result.push('\r\nProcessing time (ms): ', stats.processingTime, '\r\n\r\n');
}
statusPanel.value += result.join('');
fileCount--;
if (fileCount === 0) {
loadingIcon.style.display = 'none';
}
openTab(null, 'Status');
}
function openTab(elm, tabName) {
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
if (!elm) {
if (tabName === 'Status') {
elm = document.getElementById('StatusBtn');
} else if (tabName === 'Data') {
elm = document.getElementById('DataBtn');
}
}
elm.className += " active";
}
</script>
<style>
#myMap {
position: relative;
width: calc(100% - 375px);
min-width: 290px;
height: 600px;
float: left;
}
.sidePanel {
width: 325px;
height: 580px;
float: left;
margin-right: 10px;
}
#Instructions {
display: block;
height: 490px;
width: 306px;
}
#statusPanel {
width: 300px;
height: 490px;
overflow-y: auto;
}
#dataPanel {
width: 300px;
height: 360px;
overflow-y: auto;
}
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 6px 8px;
transition: 0.3s;
font-size: 14px;
}
.tab button:hover {
background-color: #ddd;
}
.tab button.active {
background-color: #ccc;
}
.tabcontent {
display: none;
padding: 6px 12px;
border: 1px solid #ccc;
border-top: none;
}
</style>
</head>
<body onload="getMap()">
<fieldset class="sidePanel">
<legend>Drag and drop spatial files onto map</legend>
<div class="tab">
<button class="tablinks active" onclick="openTab(this, 'Instructions')">Instructions</button>
<button id="StatusBtn" class="tablinks" onclick="openTab(this, 'Status')">Status</button>
<button id="DataBtn" class="tablinks" onclick="openTab(this, 'Data')">Data</button>
</div>
<div id="Instructions" class="tabcontent">
Drag and drop one or more KML, KMZ, GeoRSS, GPX, GML, GeoJSON or CSV files onto the map.<br /><br />
<select id="fileType">
<option>CSV</option>
<option>GeoRSS</option>
<option>GeoJSON</option>
<option>GML</option>
<option>GPX</option>
<option selected="selected">KML</option>
</select>
<input type="button" value="Write data" onclick="writeData()" />
<input type="button" value="Download Zip" onclick="downloadZip()" /><br /><br />
<input type="button" value="Clear Map" onclick="clearMap();" />
</div>
<div id="Status" class="tabcontent">
<textarea id="statusPanel"></textarea>
</div>
<div id="Data" class="tabcontent">
<textarea id="dataPanel"></textarea>
<br /><br />
Add XML, GeoJSON, CSV or an URL that points to a file of these types into the data panel and press the "Read data" button to render the data on the map.
<br /><br />
<input type="button" value="Read data" onclick="readDataPanel()" />
</div>
</fieldset>
<div id="myMap"></div>
<img id="loadingIcon" src="/images/loadingIcon.gif" style="position:absolute;top:270px;left:calc(50% - 30px);display:none;" />
</body>
</html>