ソースを参照

#90 example which uses leaflet js lib to show map.
This code lead to the creation of #112.
The use of on_page_ready callback is not "nice".

Rodja Trappe 2 年 前
コミット
ac5f8fdd84
2 ファイル変更103 行追加0 行削除
  1. 79 0
      examples/map/leaflet.py
  2. 24 0
      examples/map/main.py

+ 79 - 0
examples/map/leaflet.py

@@ -0,0 +1,79 @@
+import logging
+from typing import Dict, Optional, Tuple, Union
+
+from nicegui import ui
+from nicegui.events import ValueChangeEventArguments
+
+
+class map(ui.card):
+
+    def __init__(self):
+        super().__init__()
+        self.classes('osm-map').style('width:100%;height:300px;transition:opacity 1s;opacity:0.1')
+        self.add_leaflet_js()
+
+    async def set_location(self, location: Union[Optional[Tuple[float, float]], Dict[str, Tuple[float, float]], ValueChangeEventArguments]):
+        try:
+            if isinstance(location, ValueChangeEventArguments):
+                location = location.value
+            if isinstance(location, dict):
+                location = location.get('location', location.get('value', None))
+            if not isinstance(location, tuple) or len(location) != 2 or not all(
+                    isinstance(x, float) or isinstance(x, int) for x in location):
+                self.style('opacity: 0.1;')
+                logging.warning(f'Invalid location: {location}')
+                return
+            self.style('opacity: 1;')
+            await ui.run_javascript(f'''
+                target = L.latLng("{location[0]}", "{location[1]}")
+                map.setView(target, 9);
+                if (marker != undefined) map.removeLayer(marker);
+                marker = L.marker(target);
+                marker.addTo(map);
+                0 // return something so we do net get a js error
+            ''')
+        except:
+            logging.exception(f'could not update {location}')
+
+    @staticmethod
+    def add_leaflet_js():
+        ui.add_head_html(r'''
+        <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"></script>
+        <link href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" rel="stylesheet"/>
+        <script>
+            function waitForElm(selector) {
+                return new Promise(resolve => {
+                    if (document.querySelector(selector)) {
+                        return resolve(document.querySelector(selector));
+                    }
+
+                    const observer = new MutationObserver(mutations => {
+                        if (document.querySelector(selector)) {
+                            resolve(document.querySelector(selector));
+                            observer.disconnect();
+                        }
+                    });
+
+                    observer.observe(document.body, {
+                        childList: true,
+                        subtree: true
+                    });
+                });
+            }
+            var marker;
+            var map;
+            document.addEventListener("DOMContentLoaded", function() {
+                waitForElm('.osm-map').then((container) => {
+                    map = L.map(container);
+                    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
+                        attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
+                    }).addTo(map);                    
+                });
+            });
+        </script>
+        ''')
+
+# var target = L.latLng('53.44', '14.06'); // Fahrenwalde, Uckermark
+#                     map.setView(target, 13);
+#                     marker = L.marker(target);
+#                     marker.addTo(map);

+ 24 - 0
examples/map/main.py

@@ -0,0 +1,24 @@
+#!/usr/bin/env python3
+
+from nicegui import ui
+
+import leaflet
+
+locations = {
+    (52.5200, 13.4049): 'Berlin',
+    (40.7306, -74.0060): 'New York',
+    (39.9042, 116.4074): 'Beijing',
+    (35.6895, 139.6917): 'Tokyo',
+}
+selection = None
+
+
+@ui.page('/', on_page_ready=lambda: selection.set_value(next(iter(locations))))
+def main_page():
+    # NOTE we need to use the on_page_ready event to make sure the page is loaded before we execute javascript
+    global selection
+    map = leaflet.map()
+    selection = ui.select(locations, on_change=map.set_location).style('width: 10em')
+
+
+ui.run()