PageSourceSearch

https://hkmaps.hk/js/leaflet.filelayer.js

js hkmaps.hk collected 2026-10-02 18:36:00 UTC 11,542 bytes, 342 lines download raw bytes

1/*
2 * Load files *locally* (GeoJSON, KML, GPX) into the map
3 * using the HTML5 File API.
4 *
5 * Requires Mapbox's togeojson.js to be in global scope
6 * https://github.com/mapbox/togeojson
7 */
8
9(function (factory, window) {
10    // define an AMD module that relies on 'leaflet'
11    if (typeof define === 'function' && define.amd && window.toGeoJSON) {
12        define(['leaflet'], function (L) {
13            factory(L, window.toGeoJSON);
14        });
15    } else if (typeof module === 'object' && module.exports) {
16        // require('LIBRARY') returns a factory that requires window to
17        // build a LIBRARY instance, we normalize how we use modules
18        // that require this pattern but the window provided is a noop
19        // if it's defined
20        module.exports = function (root, L, toGeoJSON) {
21            if (L === undefined) {
22                if (typeof window !== 'undefined') {
23                    L = require('leaflet');
24                } else {
25                    L = require('leaflet')(root);
26                }
27            }
28            if (toGeoJSON === undefined) {
29                if (typeof window !== 'undefined') {
30                    toGeoJSON = require('togeojson');
31                } else {
32                    toGeoJSON = require('togeojson')(root);
33                }
34            }
35            factory(L, toGeoJSON);
36            return L;
37        };
38    } else if (typeof window !== 'undefined' && window.L && window.toGeoJSON) {
39        factory(window.L, window.toGeoJSON);
40    }
41}(function fileLoaderFactory(L, toGeoJSON) {
42    var FileLoader = L.Layer.extend({
43        options: {
44            layer: L.geoJson,
45            layerOptions: {},
46            fileSizeLimit: 1024
47        },
48
49        initialize: function (map, options) {
50            this._map = map;
51            L.Util.setOptions(this, options);
52
53            this._parsers = {
54                geojson: this._loadGeoJSON,
55                json: this._loadGeoJSON,
56                gpx: this._convertToGeoJSON,
57                kml: this._convertToGeoJSON
58            };
59        },
60
61        load: function (file, ext) {
62            var parser,
63                reader;
64
65            // Check file is defined
66            if (this._isParameterMissing(file, 'file')) {
67                return false;
68            }
69
70            // Check file size
71            if (!this._isFileSizeOk(file.size)) {
72                return false;
73            }
74
75            // Get parser for this data type
76            parser = this._getParser(file.name, ext);
77            if (!parser) {
78                return false;
79            }
80
81            // Read selected file using HTML5 File API
82            reader = new FileReader();
83            reader.onload = L.Util.bind(function (e) {
84                var layer;
85                try {
86                    this.fire('data:loading', { filename: file.name, format: parser.ext });
87                    layer = parser.processor.call(this, e.target.result, parser.ext);
88                    this.fire('data:loaded', {
89                        layer: layer,
90                        filename: file.name,
91                        format: parser.ext
92                    });
93                } catch (err) {
94                    this.fire('data:error', { error: err });
95                }
96            }, this);
97            // Testing trick: tests don't pass a real file,
98            // but an object with file.testing set to true.
99            // This object cannot be read by reader, just skip it.
100            if (!file.testing) {
101                reader.readAsText(file);
102            }
103            // We return this to ease testing
104            return reader;
105        },
106
107        loadMultiple: function (files, ext) {
108            var readers = [];
109            if (files[0]) {
110              files = Array.prototype.slice.apply(files);
111              while (files.length > 0) {
112                readers.push(this.load(files.shift(), ext));
113              }
114            }
115            // return first reader (or false if no file),
116            // which is also used for subsequent loadings
117            return readers;
118        },
119
120        loadData: function (data, name, ext) {
121            var parser;
122            var layer;
123
124            // Check required parameters
125            if ((this._isParameterMissing(data, 'data'))
126              || (this._isParameterMissing(name, 'name'))) {
127                return;
128            }
129
130            // Check file size
131            if (!this._isFileSizeOk(data.length)) {
132                return;
133            }
134
135            // Get parser for this data type
136            parser = this._getParser(name, ext);
137            if (!parser) {
138                return;
139            }
140
141            // Process data
142            try {
143                this.fire('data:loading', { filename: name, format: parser.ext });
144                layer = parser.processor.call(this, data, parser.ext);
145                this.fire('data:loaded', {
146                    layer: layer,
147                    filename: name,
148                    format: parser.ext
149                });
150            } catch (err) {
151                this.fire('data:error', { error: err });
152            }
153        },
154
155        _isParameterMissing: function (v, vname) {
156            if (typeof v === 'undefined') {
157                this.fire('data:error', {
158                    error: new Error('Missing parameter: ' + vname)
159                });
160                return true;
161            }
162            return false;
163        },
164
165        _getParser: function (name, ext) {
166            var parser;
167            ext = ext || name.split('.').pop();
168            parser = this._parsers[ext];
169            if (!parser) {
170                this.fire('data:error', {
171                    error: new Error('Unsupported file type (' + ext + ')')
172                });
173                return undefined;
174            }
175            return {
176                processor: parser,
177                ext: ext
178            };
179        },
180
181        _isFileSizeOk: function (size) {
182            var fileSize = (size / 1024).toFixed(4);
183            if (fileSize > this.options.fileSizeLimit) {
184                this.fire('data:error', {
185                    error: new Error(
186                        'File size exceeds limit (' +
187                        fileSize + ' > ' +
188                        this.options.fileSizeLimit + 'kb)'
189                    )
190                });
191                return false;
192            }
193            return true;
194        },
195
196        _loadGeoJSON: function _loadGeoJSON(content) {
197            var layer;
198            if (typeof content === 'string') {
199                content = JSON.parse(content);
200            }
201            layer = this.options.layer(content, this.options.layerOptions);
202
203            if (layer.getLayers().length === 0) {
204                throw new Error('GeoJSON has no valid layers.');
205            }
206
207            if (this.options.addToMap) {
208                layer.addTo(this._map);
209            }
210            return layer;
211        },
212
213        _convertToGeoJSON: function _convertToGeoJSON(content, format) {
214            var geojson;
215            // Format is either 'gpx' or 'kml'
216            if (typeof content === 'string') {
217                content = (new window.DOMParser()).parseFromString(content, 'text/xml');
218            }
219            geojson = toGeoJSON[format](content);
220            return this._loadGeoJSON(geojson);
221        }
222    });
223
224    var FileLayerLoad = L.Control.extend({
225        statics: {
226            TITLE: 'Load local file (GPX, KML, GeoJSON)',
227            LABEL: '⌅'
228        },
229        options: {
230            position: 'topright',
231            fitBounds: true,
232            layerOptions: {},
233            addToMap: true,
234            fileSizeLimit: 1024
235        },
236
237        initialize: function (options) {
238            L.Util.setOptions(this, options);
239            this.loader = null;
240        },
241
242        onAdd: function (map) {
243            this.loader = L.FileLayer.fileLoader(map, this.options);
244
245            this.loader.on('data:loaded', function (e) {
246                // Fit bounds after loading
247                if (this.options.fitBounds) {
248                    window.setTimeout(function () {
249                        map.fitBounds(e.layer.getBounds());
250                    }, 500);
251                }
252            }, this);
253
254            // Initialize Drag-and-drop
255            this._initDragAndDrop(map);
256
257            // Initialize map control
258            return this._initContainer();
259        },
260
261        _initDragAndDrop: function (map) {
262            var callbackName;
263            var thisLoader = this.loader;
264            var dropbox = map._container;
265
266            var callbacks = {
267                dragenter: function () {
268                    map.scrollWheelZoom.disable();
269                },
270                dragleave: function () {
271                    map.scrollWheelZoom.enable();
272                },
273                dragover: function (e) {
274                    e.stopPropagation();
275                    e.preventDefault();
276                },
277                drop: function (e) {
278                    e.stopPropagation();
279                    e.preventDefault();
280
281                    thisLoader.loadMultiple(e.dataTransfer.files);
282                    map.scrollWheelZoom.enable();
283                }
284            };
285            for (callbackName in callbacks) {
286                if (callbacks.hasOwnProperty(callbackName)) {
287                    dropbox.addEventListener(callbackName, callbacks[callbackName], false);
288                }
289            }
290        },
291
292        _initContainer: function () {
293            var thisLoader = this.loader;
294
295            // Create a button, and bind click on hidden file input
296            var fileInput;
297            var zoomName = 'leaflet-control-filelayer leaflet-control-zoom';
298            var barName = 'leaflet-bar';
299            var partName = barName + '-part';
300            var container = L.DomUtil.create('div', zoomName + ' ' + barName);
301            var link = L.DomUtil.create('a', zoomName + '-in ' + partName, container);
302            link.innerHTML = L.Control.FileLayerLoad.LABEL;
303            link.href = '#';
304            link.title = L.Control.FileLayerLoad.TITLE;
305
306            // Create an invisible file input
307            fileInput = L.DomUtil.create('input', 'hidden', container);
308            fileInput.type = 'file';
309            fileInput.multiple = 'multiple';
310            if (!this.options.formats) {
311                fileInput.accept = '.gpx,.kml,.json,.geojson';
312            } else {
313                fileInput.accept = this.options.formats.join(',');
314            }
315            fileInput.style.display = 'none';
316            // Load on file change
317            fileInput.addEventListener('change', function () {
318                thisLoader.loadMultiple(this.files);
319                // reset so that the user can upload the same file again if they want to
320                this.value = '';
321            }, false);
322
323            L.DomEvent.disableClickPropagation(container);
324            L.DomEvent.on(link, 'click', function (e) {
325                fileInput.click();
326                e.preventDefault();
327            });
328            return container;
329        }
330    });
331
332    L.FileLayer = {};
333    L.FileLayer.FileLoader = FileLoader;
334    L.FileLayer.fileLoader = function (map, options) {
335        return new L.FileLayer.FileLoader(map, options);
336    };
337
338    L.Control.FileLayerLoad = FileLayerLoad;
339    L.Control.fileLayerLoad = function (options) {
340        return new L.Control.FileLayerLoad(options);
341    };
342}, window));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.