diff --git a/packages/geojson-extension/package.json b/packages/geojson-extension/package.json index 047f182e5..46d213e86 100644 --- a/packages/geojson-extension/package.json +++ b/packages/geojson-extension/package.json @@ -24,10 +24,12 @@ "@jupyterlab/rendermime-interfaces": "^1.0.3", "@phosphor/messaging": "^1.2.2", "@phosphor/widgets": "^1.5.0", - "leaflet": "^1.2.0" + "@turf/bbox": "^6.0.1", + "leaflet": "^1.2.0", + "mapbox-gl": "^0.44.2" }, "devDependencies": { - "@types/leaflet": "^1.2.0", + "@types/mapbox-gl": "^0.44.1", "rimraf": "~2.6.2", "typescript": "~2.6.2" }, diff --git a/packages/geojson-extension/src/index.tsx b/packages/geojson-extension/src/index.tsx index 918c318ad..424344f41 100644 --- a/packages/geojson-extension/src/index.tsx +++ b/packages/geojson-extension/src/index.tsx @@ -13,15 +13,14 @@ import { IRenderMime } from '@jupyterlab/rendermime-interfaces'; -import * as leaflet from 'leaflet'; +import mapboxgl = require('mapbox-gl'); + +import bbox from '@turf/bbox'; import 'leaflet/dist/leaflet.css'; import '../style/index.css'; -import * as iconRetinaUrl from 'leaflet/dist/images/marker-icon-2x.png'; -import * as iconUrl from 'leaflet/dist/images/marker-icon.png'; -import * as shadowUrl from 'leaflet/dist/images/marker-shadow.png'; /** * The CSS class to add to the GeoJSON Widget. @@ -39,39 +38,7 @@ const CSS_ICON_CLASS = 'jp-MaterialIcon jp-GeoJSONIcon'; export const MIME_TYPE = 'application/geo+json'; -/** - * Set base path for leaflet images. - */ - -// https://github.com/Leaflet/Leaflet/issues/4968 -// Marker file names are hard-coded in the leaflet source causing -// issues with webpack. -// This workaround allows webpack to inline all marker URLs. - -delete (leaflet.Icon.Default.prototype as any)['_getIconUrl']; - -leaflet.Icon.Default.mergeOptions({ - iconRetinaUrl: iconRetinaUrl, - iconUrl: iconUrl, - shadowUrl: shadowUrl -}); - - -/** - * The url template that leaflet tile layers. - * See http://leafletjs.com/reference-1.0.3.html#tilelayer - */ -const URL_TEMPLATE: string = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; - -/** - * The options for leaflet tile layers. - * See http://leafletjs.com/reference-1.0.3.html#tilelayer - */ -const LAYER_OPTIONS: leaflet.TileLayerOptions = { - attribution: 'Map data (c) <a href="https://openstreetmap.org">OpenStreetMap</a> contributors', - minZoom: 0, - maxZoom: 18 -}; +mapboxgl.accessToken = 'pk.eyJ1IjoibWlja3QiLCJhIjoiLXJIRS1NbyJ9.EfVT76g4A5dyuApW_zuIFQ'; export @@ -82,14 +49,7 @@ class RenderedGeoJSON extends Widget implements IRenderMime.IRenderer { constructor(options: IRenderMime.IRendererOptions) { super(); this.addClass(CSS_CLASS); - this._mimeType = options.mimeType; - // Create leaflet map object - // trackResize option set to false as it is not needed to track - // window.resize events since we have individual phosphor resize - // events. - this._map = leaflet.map(this.node, { - trackResize: false - }); + this._mimeType = options.mimeType; } /** @@ -107,17 +67,35 @@ class RenderedGeoJSON extends Widget implements IRenderMime.IRenderer { */ renderModel(model: IRenderMime.IMimeModel): Promise<void> { const data = model.data[this._mimeType] as any | GeoJSON.GeoJsonObject; - const metadata = model.metadata[this._mimeType] as any || {}; + // const metadata = model.metadata[this._mimeType] as any || {}; + this._map = new mapboxgl.Map({ + container: this.node, + style: 'mapbox://styles/mapbox/streets-v9?optimize=true', + zoom: 10 + }); return new Promise<void>((resolve, reject) => { - // Add leaflet tile layer to map - leaflet.tileLayer( - metadata.url_template || URL_TEMPLATE, - metadata.layer_options || LAYER_OPTIONS - ).addTo(this._map); - // Create GeoJSON layer from data and add to map - this._geoJSONLayer = leaflet.geoJSON(data).addTo(this._map); - this.update(); - resolve(); + // Add GeoJSON layer to map + this._map.on('style.load', () => { + this._map.addSource('geojson', { + type: 'geojson', + data + }); + const [minX, minY, maxX, maxY] = bbox(data); + this._map.fitBounds([[minX, minY], [maxX, maxY]], { maxZoom: 15, padding: 100 }); + this._map.addLayer({ + id: 'geojson-points', + type: 'circle', + source: 'geojson', + paint: { + 'circle-color': 'red', + 'circle-stroke-color': 'white', + 'circle-stroke-width': { stops: [[0,0.1], [18,3]], base: 1.2 }, + 'circle-radius': { stops: [[15,3], [18,5]], base: 1.2 } + } + }); + this.update(); + resolve(); + }); }); } @@ -125,19 +103,20 @@ class RenderedGeoJSON extends Widget implements IRenderMime.IRenderer { * A message handler invoked on an `'after-attach'` message. */ protected onAfterAttach(msg: Message): void { - if (this.parent.hasClass('jp-OutputArea-child')) { - // Disable scroll zoom by default to avoid conflicts with notebook scroll - this._map.scrollWheelZoom.disable(); - // Enable scroll zoom on map focus - this._map.on('blur', (event) => { - this._map.scrollWheelZoom.disable(); - }); - // Disable scroll zoom on blur - this._map.on('focus', (event) => { - this._map.scrollWheelZoom.enable(); - }); - } - this.update(); + // If in a notebook context + // if (this.parent.hasClass('jp-OutputArea-child')) { + // // Disable scroll zoom by default to avoid conflicts with notebook scroll + // this._map.scrollZoom.disable(); + // // Enable scroll zoom on map focus + // this._map.on('blur', (event: Event) => { + // this._map.scrollZoom.disable(); + // }); + // // Disable scroll zoom on blur + // this._map.on('focus', (event: Event) => { + // this._map.scrollZoom.enable(); + // }); + // } + // this.update(); } /** @@ -159,13 +138,13 @@ class RenderedGeoJSON extends Widget implements IRenderMime.IRenderer { */ protected onUpdateRequest(msg: Message): void { // Update map size after update - if (this.isVisible) this._map.invalidateSize(); - // Update map size after panel/window is resized - this._map.fitBounds(this._geoJSONLayer.getBounds()); + if (this._map && this.isVisible) { + this._map.resize(); + } } - private _map: leaflet.Map; - private _geoJSONLayer: leaflet.GeoJSON; + private _map: mapboxgl.Map; + // private _geoJSONLayer: mapboxgl.GeoJSONSource; private _mimeType: string; } diff --git a/yarn.lock b/yarn.lock index 9d29cb421..d1a559a8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -311,6 +311,23 @@ d3-collection "1" d3-interpolate "1" +"@turf/bbox@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/@turf/bbox/-/bbox-6.0.1.tgz#b966075771475940ee1c16be2a12cf389e6e923a" + dependencies: + "@turf/helpers" "6.x" + "@turf/meta" "6.x" + +"@turf/helpers@6.x": + version "6.1.3" + resolved "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.3.tgz#0001a5c4a3bff25b4bbbc64f8713a383c9ab9e94" + +"@turf/meta@6.x": + version "6.0.1" + resolved "https://registry.npmjs.org/@turf/meta/-/meta-6.0.1.tgz#cf6f3f2263a3d24fc8d6a7e90f0420bbc44c090d" + dependencies: + "@turf/helpers" "6.x" + "@types/d3-array@*": version "1.2.1" resolved "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.1.tgz#e489605208d46a1c9d980d2e5772fa9c75d9ec65" @@ -503,9 +520,9 @@ version "0.5.0" resolved "https://registry.npmjs.org/@types/katex/-/katex-0.5.0.tgz#a7dbb981f1bc89c8b1b5e7fa8a1ce2617ab2f358" -"@types/leaflet@^1.2.0": - version "1.2.5" - resolved "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.2.5.tgz#b172502c298849cadd034314dabfc936beff7636" +"@types/mapbox-gl@^0.44.1": + version "0.44.1" + resolved "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-0.44.1.tgz#6d8618ab2a28e8b78ce2cca403f28a227c9f217d" dependencies: "@types/geojson" "*" @@ -3439,6 +3456,42 @@ mapbox-gl@^0.44.0: vt-pbf "^3.0.1" webworkify "^1.5.0" +mapbox-gl@^0.44.2: + version "0.44.2" + resolved "https://registry.npmjs.org/mapbox-gl/-/mapbox-gl-0.44.2.tgz#8c118ba8c5c15b054272644f30877309db0f8ee2" + dependencies: + "@mapbox/gl-matrix" "^0.0.1" + "@mapbox/mapbox-gl-supported" "^1.3.0" + "@mapbox/point-geometry" "^0.1.0" + "@mapbox/shelf-pack" "^3.1.0" + "@mapbox/tiny-sdf" "^1.1.0" + "@mapbox/unitbezier" "^0.0.0" + "@mapbox/vector-tile" "^1.3.0" + "@mapbox/whoots-js" "^3.0.0" + brfs "^1.4.0" + bubleify "^0.7.0" + csscolorparser "~1.0.2" + earcut "^2.1.3" + geojson-rewind "^0.3.0" + geojson-vt "^3.0.0" + gray-matter "^3.0.8" + grid-index "^1.0.0" + jsonlint-lines-primitives "~1.6.0" + minimist "0.0.8" + package-json-versionify "^1.0.2" + pbf "^3.0.5" + quickselect "^1.0.0" + rw "^1.3.3" + shuffle-seed "^1.1.6" + sort-object "^0.3.2" + supercluster "^2.3.0" + through2 "^2.0.3" + tinyqueue "^1.1.0" + unassertify "^2.0.0" + unflowify "^1.0.0" + vt-pbf "^3.0.1" + webworkify "^1.5.0" + marching-simplex-table@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/marching-simplex-table/-/marching-simplex-table-1.0.0.tgz#bc16256e0f8f9b558aa9b2872f8832d9433f52ea"