UNPKG

leaflet-kmz

Version:

A KMZ file loader for Leaflet Maps

294 lines (254 loc) 9.29 kB
/** * A plugin combining geojson-vt with leafletjs which is initially inspired by leaflet-geojson-vt. * * @author Brandonxiang, Raruto * * @link https://github.com/brandonxiang/leaflet-geojson-vt */ // import geojsonvt from 'geojson-vt'; import 'leaflet-pointable'; L.GridLayer.GeoJSON = L.GridLayer.extend({ options: { pointable: false, ballon: false, bindPopup: false, bindTooltip: false, async: false, maxZoom: 24, tolerance: 3, debug: 0, extent: 4096, buffer: 256, icon: { width: 28, height: 28 }, styles: { strokeWidth: 1, strokeColor: '#f00', strokeOpacity: 1.0, fillColor: '#000', fillOpacity: 0.25 } }, initialize: function(geojson, options) { L.setOptions(this, options); L.GridLayer.prototype.initialize.call(this, options); this.tileIndex = (geojsonvt || window.geojsonvt)(geojson, this.options); this.geojson = geojson; // eg. saved for advanced "leaflet-pip" mouse/click integrations }, onAdd: function(map) { L.GridLayer.prototype.onAdd.call(this, map); if (this.options.ballon) { if (this.options.bindPopup) this._map.on("click", this.updateBalloon, this); if (this.options.bindTooltip) this._map.on("mousemove", this.updateBalloon, this); } }, createTile: function(coords) { var tile = L.DomUtil.create('canvas', 'leaflet-tile'); var size = this.getTileSize(); tile.width = size.x; tile.height = size.y; var ctx = tile.getContext('2d'); // return the tile so it can be rendered on screen var tileInfo = this.tileIndex.getTile(coords.z, coords.x, coords.y); var features = tileInfo ? tileInfo.features : []; for (var i = 0; i < features.length; i++) { this._drawFeature(ctx, features[i]); } return tile; }, _drawFeature: function(ctx, feature) { ctx.beginPath(); this._setStyle(ctx, feature); if (feature.type === 1) this._drawIcon(ctx, feature); else if (feature.type === 2) this._drawLine(ctx, feature); else if (feature.type === 3) this._drawPolygon(ctx, feature); else console.warn('Unsupported feature type: ' + feature.geometry.type, feature); ctx.stroke(); }, _drawIcon: function(ctx, feature) { var icon = new Image(), p = feature.geometry[0], width = this.options.icon.width, height = this.options.icon.height; icon.onload = function() { ctx.drawImage(icon, (p[0] / 16.0) - (width / 2.0), (p[1] / 16.0) - (height / 2.0), width, height); }; icon.src = feature.tags.icon ? feature.tags.icon : null; }, _drawLine: function(ctx, feature) { for (var j = 0; j < feature.geometry.length; j++) { var ring = feature.geometry[j]; for (var k = 0; k < ring.length; k++) { var p = ring[k]; if (k) ctx.lineTo(p[0] / 16.0, p[1] / 16.0); else ctx.moveTo(p[0] / 16.0, p[1] / 16.0); } } }, _drawPolygon: function(ctx, feature) { this._drawLine(ctx, feature); ctx.fill('evenodd'); }, _setStyle: function(ctx, feature) { var style = {}; if (feature.type === 1) style = this._setPointStyle(feature, style); else if (feature.type === 2) style = this._setLineStyle(feature, style); else if (feature.type === 3) style = this._setPolygonStyle(feature, style); ctx.lineWidth = style.stroke ? this._setWeight(style.weight) : 0; ctx.strokeStyle = style.stroke ? this._setOpacity(style.stroke, style.opacity) : {}; ctx.fillStyle = style.fill ? this._setOpacity(style.fill, style.fillOpacity) : {}; }, _setPointStyle: function(feature, style) { return style; }, _setLineStyle: function(feature, style) { style.weight = (feature.tags["stroke-width"] ? feature.tags["stroke-width"] : this.options.styles.strokeWidth) * 1.05; style.opacity = feature.tags["stroke-opacity"] ? feature.tags["stroke-opacity"] : this.options.styles.strokeOpacity; style.stroke = feature.tags.stroke ? feature.tags.stroke : this.options.styles.strokeColor; return style; }, _setPolygonStyle: function(feature, style) { style = this._setLineStyle(feature, style); style.fill = feature.tags.fill ? feature.tags.fill : this.options.styles.fillColor; style.fillOpacity = feature.tags["fill-opacity"] ? feature.tags["fill-opacity"] : this.options.styles.fillOpacity; return style; }, _setWeight: function(weight) { return weight || 5; }, _setOpacity: function(color, opacity) { color = color || '#f00'; if (opacity && this._iscolorHex(color)) { var colorRgb = this._colorRgb(color); return "rgba(" + colorRgb[0] + "," + colorRgb[1] + "," + colorRgb[2] + "," + opacity + ")"; } return color; }, _iscolorHex: function(color) { return /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/.test(color.toLowerCase()); }, _colorRgb: function(color) { var sColor = color.toLowerCase(); if (sColor.length === 4) { var sColorNew = "#"; for (var i = 1; i < 4; i += 1) { sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)); } sColor = sColorNew; } var sColorChange = []; for (var j = 1; j < 7; j += 2) { sColorChange.push(parseInt("0x" + sColor.slice(j, j + 2))); } return sColorChange; }, /** * Point in Polygon: ray-casting algorithm * * @link http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html */ _pointInPolygon: function(point, vs) { var x = point[0]; var y = point[1]; var inside = false; for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) { var xi = vs[i][0]; var yi = vs[i][1]; var xj = vs[j][0]; var yj = vs[j][1]; var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) inside = !inside; } return inside; }, _getLatLngsPoly: function(feature, i) { var o = []; var geometry = feature.geometry || feature; var coords = geometry.type == "Polygon" ? geometry.coordinates[0] : geometry.coordinates; for (var j = i || 0; j < coords.length; j++) { o[i++] = [coords[j][0], coords[j][1]]; } return o.length ? o : false; }, _getLatLngsPoint: function(feature, i) { var o = []; var geometry = feature.geometry || feature; var coords = geometry.coordinates; o[i || 0] = [coords[0], coords[1]]; return o.length ? o : false; }, _getLatLngs: function(feature, i) { var o = []; i = i || 0; var coords; var geometry = feature.geometry || feature; var type = geometry.type; if (type == "Point") { coords = this._getLatLngsPoint(feature, i); if (coords) Array.prototype.push.apply(o, coords); } else if (type == "LineString" || type == "Polygon") { coords = this._getLatLngsPoly(feature, i); if (coords) Array.prototype.push.apply(o, coords); } else if (type == "GeometryCollection") { var polys = geometry.geometries; for (var j = 0; j < polys.length; j++) { coords = this._getLatLngs(polys[j], i); if (coords) Array.prototype.push.apply(o, coords); } } else { console.warn("Unsupported feature type: " + type); } return o.length ? o : false; }, /** * (EXPERIMENTAL) Inspired by: https://github.com/mapbox/leaflet-pip * * TODO: add/check support for Points, Lines and "donuts" Polygons */ pointInLayer: function(p, layer, first) { if (p instanceof L.LatLng) p = [p.lng, p.lat]; var results = []; layer = layer || this.geojson; first = first || true; var features = layer.features; for (var i = 0; i < features.length; i++) { if (first && results.length) break; var coords = this._getLatLngs(features[i]); if (coords) { var inside = this._pointInPolygon(p, coords); // NB. works only with polygons (see: https://observablehq.com/@tmcw/understanding-point-in-polygon). if (inside) results.push(features[i]); } } return results.length ? results : false; }, /** * (EXPERIMENTAL) Inspired by: https://github.com/Raruto/leaflet-pointable */ updateBalloon: function(e) { if (!this._map || !this.options.pointable || !this._map.isPointablePixel() || !this.isPointablePixel()) return; this._popup = this._popup || new L.Popup(); var points = this.pointInLayer(e.latlng, this.geojson); if (points) { var feature = points[0]; var name = feature.properties.name || ""; if (name) { this._popup.setLatLng(e.latlng); this._popup.setContent('<b>' + name + '</b>'); this._popup.openOn(this._map); } } else { this._map.closePopup(this._popup); } }, }); L.gridLayer.geoJson = function(geojson, options) { return new L.GridLayer.GeoJSON(geojson, options); }; export var GridLayer = { GeoJSON: L.GridLayer.GeoJSON, }; export var gridLayer = { geoJSON: L.gridLayer.geoJson, };