Browse Source

Add geojson-extension

Grant Nestor 7 years ago
parent
commit
efa2ad0412

+ 2 - 0
jupyterlab/package.app.json

@@ -34,6 +34,7 @@
     "@jupyterlab/filebrowser-extension": "^0.11.1",
     "@jupyterlab/fileeditor": "^0.11.1",
     "@jupyterlab/fileeditor-extension": "^0.11.1",
+    "@jupyterlab/geojson-extension": "^0.11.0",
     "@jupyterlab/help-extension": "^0.11.1",
     "@jupyterlab/imageviewer": "^0.11.1",
     "@jupyterlab/imageviewer-extension": "^0.11.1",
@@ -109,6 +110,7 @@
       "@jupyterlab/tooltip-extension": ""
     },
     "mimeExtensions": {
+      "@jupyterlab/geojson-extension": "",
       "@jupyterlab/json-extension": "",
       "@jupyterlab/pdf-extension": "",
       "@jupyterlab/vdom-extension": "",

+ 3 - 0
jupyterlab/package.json

@@ -32,6 +32,7 @@
     "@jupyterlab/filebrowser-extension": "^0.11.1",
     "@jupyterlab/fileeditor": "^0.11.1",
     "@jupyterlab/fileeditor-extension": "^0.11.1",
+    "@jupyterlab/geojson-extension": "^0.11.0",
     "@jupyterlab/help-extension": "^0.11.1",
     "@jupyterlab/imageviewer": "^0.11.1",
     "@jupyterlab/imageviewer-extension": "^0.11.1",
@@ -108,6 +109,7 @@
       "@jupyterlab/tooltip-extension": ""
     },
     "mimeExtensions": {
+      "@jupyterlab/geojson-extension": "",
       "@jupyterlab/json-extension": "",
       "@jupyterlab/pdf-extension": "",
       "@jupyterlab/vdom-extension": "",
@@ -159,6 +161,7 @@
       "@jupyterlab/filebrowser-extension": "../packages/filebrowser-extension",
       "@jupyterlab/fileeditor": "../packages/fileeditor",
       "@jupyterlab/fileeditor-extension": "../packages/fileeditor-extension",
+      "@jupyterlab/geojson-extension": "../packages/geojson-extension",
       "@jupyterlab/help-extension": "../packages/help-extension",
       "@jupyterlab/imageviewer": "../packages/imageviewer",
       "@jupyterlab/imageviewer-extension": "../packages/imageviewer-extension",

+ 92 - 0
packages/geojson-extension/README.md

@@ -0,0 +1,92 @@
+# geojson-extension
+
+A JupyterLab extension for rendering GeoJSON
+
+![demo](http://g.recordit.co/I3OcBu8RUe.gif)
+
+## Prerequisites
+
+* JupyterLab ^0.27.0
+
+## Usage
+
+To render GeoJSON output in IPython:
+
+```python
+from IPython.display import GeoJSON
+
+GeoJSON({
+    "type": "Feature",
+    "geometry": {
+        "type": "Point",
+        "coordinates": [-118.4563712, 34.0163116]
+    }
+})
+```
+
+To use a specific tileset:
+
+```python
+GeoJSON(data={
+    "type": "Feature",
+    "geometry": {
+        "type": "Point",
+        "coordinates": [-118.4563712, 34.0163116]
+    }
+}, url_template="https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=[MAPBOX_ACCESS_TOKEN]", 
+layer_options={
+    "id": "mapbox.streets",
+    "attribution" : '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
+})
+```
+
+To render GeoJSON on Mars:
+
+```python
+GeoJSON(data={
+    "type": "Feature",
+    "geometry": {
+        "type": "Point",
+        "coordinates": [11.8, -45.04]
+    }
+}, url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png", 
+layer_options={
+    "basemap_id": "celestia_mars-shaded-16k_global",
+    "attribution" : "Celestia/praesepe",
+    "tms": True,
+    "minZoom" : 0,
+    "maxZoom" : 5
+})
+```
+
+To render a `.geojson` or `.geo.json` file, simply open it:
+
+## Install
+
+```bash
+jupyter labextension install @jupyterlab/geojson-extension
+```
+
+## Development
+
+```bash
+# Clone the repo to your local environment
+git clone https://github.com/jupyterlab/jupyter-renderers.git
+cd jupyter-renderers
+# Install dependencies
+npm install
+# Build Typescript source
+npm run build
+# Link your development version of the extension with JupyterLab
+jupyter labextension link packages/geojson-extension
+# Rebuild Typescript source after making changes
+npm run build
+# Rebuild JupyterLab after making any changes
+jupyter lab build
+```
+
+## Uninstall
+
+```bash
+jupyter labextension uninstall @jupyterlab/geojson-extension
+```

+ 43 - 0
packages/geojson-extension/package.json

@@ -0,0 +1,43 @@
+{
+  "name": "@jupyterlab/geojson-extension",
+  "version": "0.11.0",
+  "description": "JupyterLab - GeoJSON Renderer",
+  "main": "lib/index.js",
+  "types": "lib/index.d.ts",
+  "files": [
+    "lib/*.d.ts",
+    "lib/*.js",
+    "style/*"
+  ],
+  "directories": {
+    "lib": "lib/"
+  },
+  "jupyterlab": {
+    "mimeExtension": true
+  },
+  "dependencies": {
+    "@jupyterlab/rendermime-interfaces": "^0.4.0",
+    "@phosphor/widgets": "^1.3.0",
+    "leaflet": "^1.2.0"
+  },
+  "devDependencies": {
+    "@types/leaflet": "^1.2.0",
+    "rimraf": "^2.5.2",
+    "typescript": "~2.4.1"
+  },
+  "scripts": {
+    "build": "tsc",
+    "clean": "rimraf lib",
+    "watch": "tsc -w"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/jupyterlab/jupyter-renderers.git"
+  },
+  "author": "Project Jupyter",
+  "license": "BSD-3-Clause",
+  "bugs": {
+    "url": "https://github.com/jupyterlab/jupyter-renderers/issues"
+  },
+  "homepage": "https://github.com/jupyterlab/jupyter-renderers"
+}

+ 168 - 0
packages/geojson-extension/src/index.tsx

@@ -0,0 +1,168 @@
+// Copyright (c) Jupyter Development Team.
+// Distributed under the terms of the Modified BSD License.
+
+import {
+  Widget
+} from '@phosphor/widgets';
+
+import {
+  Message
+} from '@phosphor/messaging';
+
+import {
+  IRenderMime
+} from '@jupyterlab/rendermime-interfaces';
+
+import * as leaflet from 'leaflet';
+
+import 'leaflet/dist/leaflet.css';
+
+import '../style/index.css';
+
+
+/**
+ * The CSS class to add to the GeoJSON Widget.
+ */
+const CSS_CLASS = 'jp-RenderedGeoJSON';
+
+/**
+ * The CSS class for a GeoJSON icon.
+ */
+const CSS_ICON_CLASS = 'jp-MaterialIcon jp-GeoJSONIcon';
+
+/**
+ * The MIME type for GeoJSON.
+ */
+export
+const MIME_TYPE = 'application/geo+json';
+
+/**
+ * Set base path for leaflet images.
+ */
+leaflet.Icon.Default.imagePath = 'https://unpkg.com/leaflet/dist/images/';
+
+/**
+ * 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
+};
+
+
+export
+class RenderedGeoJSON extends Widget implements IRenderMime.IRenderer {
+  /**
+   * Create a new widget for rendering GeoJSON.
+   */
+  constructor(options: IRenderMime.IRendererOptions) {
+    super();
+    this.addClass(CSS_CLASS);
+    this._mimeType = options.mimeType;
+  }
+
+  /**
+   * Dispose of the widget.
+   */
+  dispose(): void {
+    // Dispose of leaflet map
+    this._map.remove();
+    this._map = null;
+    super.dispose();
+  }
+
+  /**
+   * Render GeoJSON into this widget's node.
+   */
+  renderModel(model: IRenderMime.IMimeModel): Promise<void> {
+    const data = model.data[this._mimeType] as any | GeoJSON.GeoJsonObject;
+    const metadata = model.metadata[this._mimeType] as any || {};
+    return new Promise<void>((resolve, reject) => {
+      // Create leaflet map object
+      this._map = leaflet.map(this.node);
+      // 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();
+      });
+      // 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);
+      resolve(undefined);
+    });
+  }
+  
+  /**
+   * A message handler invoked on a `'after-attach'` message.
+   */
+  protected onAfterAttach(msg: Message) {
+    // Set map size after widget is attached to DOM
+    this._map.fitBounds(this._geoJSONLayer.getBounds());
+    this._map.invalidateSize();
+  }
+
+  /**
+   * A message handler invoked on a `'resize'` message.
+   */
+  protected onResize(msg: Widget.ResizeMessage) {
+    // Update map size after panel/window is resized
+    this._map.fitBounds(this._geoJSONLayer.getBounds());
+    this._map.invalidateSize();
+  }
+
+  private _map: leaflet.Map;
+  private _geoJSONLayer: leaflet.GeoJSON;
+  private _mimeType: string;
+}
+
+
+/**
+ * A mime renderer factory for GeoJSON data.
+ */
+export
+const rendererFactory: IRenderMime.IRendererFactory = {
+  safe: true,
+  mimeTypes: [MIME_TYPE],
+  createRenderer: options => new RenderedGeoJSON(options)
+};
+
+
+const extensions: IRenderMime.IExtension | IRenderMime.IExtension[] = [
+  {
+    id: '@jupyterlab/geojson-extension:factory',
+    rendererFactory,
+    rank: 0,
+    dataType: 'json',
+    fileTypes: [{
+      name: 'geojson',
+      mimeTypes: [MIME_TYPE],
+      extensions: ['.geojson', '.geo.json'],
+      iconClass: CSS_ICON_CLASS
+    }],
+    documentWidgetFactoryOptions: {
+      name: 'GeoJSON',
+      primaryFileType: 'geojson',
+      fileTypes: ['geojson', 'json'],
+      defaultFor: ['geojson']
+    }
+  }
+];
+
+export default extensions;

+ 13 - 0
packages/geojson-extension/style/geojson.svg

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 42 (36781) - http://www.bohemiancoding.com/sketch -->
+    <title>geojson</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="geojson" transform="translate(-6.000000, -6.000000)">
+            <path d="M17.6666667,6 L17.56,6.02 L14,7.4 L10,6 L6.24,7.26666667 C6.1,7.31333333 6,7.43333333 6,7.58666667 L6,17.6666667 C6,17.8533333 6.14666667,18 6.33333333,18 L6.44,17.98 L10,16.6 L14,18 L17.76,16.7333333 C17.9,16.6866667 18,16.5666667 18,16.4133333 L18,6.33333333 C18,6.14666667 17.8533333,6 17.6666667,6 Z M14,16.6666667 L10,15.26 L10,7.33333333 L14,8.74 L14,16.6666667 Z" id="Shape" fill="#1BB233" fill-rule="nonzero"></path>
+            <polygon id="Shape" points="0 0 24 0 24 24 0 24"></polygon>
+        </g>
+    </g>
+</svg>

+ 32 - 0
packages/geojson-extension/style/index.css

@@ -0,0 +1,32 @@
+/**
+  Copyright (c) Jupyter Development Team.
+  Distributed under the terms of the Modified BSD License.
+*/
+
+/* Add CSS variables to :root */
+:root {
+  --jp-icon-geojson: url('./geojson.svg');
+}
+
+/* Base styles */
+.jp-RenderedGeoJSON.leaflet-container {
+  width: 100%;
+  height: 100%;
+  padding: 0;
+  overflow: hidden;
+}
+
+/* Document styles */
+.jp-MimeDocument .jp-RenderedGeoJSON {
+  
+}
+
+/* Document styles */
+.jp-OutputArea .jp-RenderedGeoJSON {
+  height: 360px;
+}
+
+/* Document icon */
+.jp-GeoJSONIcon {
+  background-image: var(--jp-icon-geojson);
+}

+ 16 - 0
packages/geojson-extension/tsconfig.json

@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "declaration": true,
+    "noImplicitAny": true,
+    "noEmitOnError": true,
+    "noUnusedLocals": true,
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "target": "ES5",
+    "outDir": "./lib",
+    "lib": ["ES5", "ES2015.Promise", "DOM", "ES2015.Collection", "es2016"],
+    "jsx": "react",
+    "types": []
+  },
+  "include": ["src/*"]
+}

+ 1 - 0
packages/metapackage/package.json

@@ -55,6 +55,7 @@
     "@jupyterlab/filebrowser-extension": "^0.11.1",
     "@jupyterlab/fileeditor": "^0.11.1",
     "@jupyterlab/fileeditor-extension": "^0.11.1",
+    "@jupyterlab/geojson-extension": "^0.11.0",
     "@jupyterlab/help-extension": "^0.11.1",
     "@jupyterlab/imageviewer": "^0.11.1",
     "@jupyterlab/imageviewer-extension": "^0.11.1",