{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Leaflet 地图\n", "\n", "这个元素是[Leaflet](https://leafletjs.com/) JavaScript库的包装器。\n", "\n", "- `center`: 地图的初始中心位置(纬度/经度,默认值:`(0.0, 0.0)`)\n", "- `zoom`: 地图的初始缩放级别(默认值:`13`)\n", "- `draw_control`: 是否显示绘图工具栏(默认值:`False`)\n", "- `options`: 传递给Leaflet地图的其他选项(默认值:`{}`)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09))\n", "ui.label().bind_text_from(m, 'center', lambda center: f'Center: {center[0]:.3f}, {center[1]:.3f}')\n", "ui.label().bind_text_from(m, 'zoom', lambda zoom: f'Zoom: {zoom}')\n", "\n", "with ui.grid(columns=2):\n", " ui.button('London', on_click=lambda: m.set_center((51.505, -0.090)))\n", " ui.button('Berlin', on_click=lambda: m.set_center((52.520, 13.405)))\n", " ui.button(icon='zoom_in', on_click=lambda: m.set_zoom(m.zoom + 1))\n", " ui.button(icon='zoom_out', on_click=lambda: m.set_zoom(m.zoom - 1))\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 想更改地图样式\n", "\n", "默认的地图样式是OpenStreetMap。您可以在 找到更多的地图样式。每次调用`tile_layer`都会叠加在前面的图层上。因此,如果您想更改地图样式,必须先移除默认的样式。" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "TileLayer(leaflet=, id='d4a42bb8-4b5d-4320-a1e1-ac861a342694', url_template='https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', options={'maxZoom': 17, 'attribution': 'Map data: © OpenStreetMap contributors, SRTM | Map style: © OpenTopoMap (CC-BY-SA)'})" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.090), zoom=3)\n", "m.clear_layers()\n", "m.tile_layer(\n", " url_template=r'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png',\n", " options={\n", " 'maxZoom': 17,\n", " 'attribution':\n", " 'Map data: © OpenStreetMap contributors, SRTM | '\n", " 'Map style: © OpenTopoMap (CC-BY-SA)'\n", " },\n", ")\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 添加标记\n", "\n", "您可以使用`marker`在地图上添加标记。`center`参数是一个包含纬度和经度的元组。这个演示通过点击地图来添加标记。请注意,`\"map-click\"`事件是指地图对象的点击事件,而`\"click\"`事件是指容器`div`的点击事件。" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import events, ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09))\n", "\n", "def handle_click(e: events.GenericEventArguments):\n", " lat = e.args['latlng']['lat']\n", " lng = e.args['latlng']['lng']\n", " m.marker(latlng=(lat, lng))\n", "m.on('map-click', handle_click)\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 移到标记\n", "\n", "您可以使用`move`方法移动标记。" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09))\n", "marker = m.marker(latlng=m.center)\n", "ui.button('Move marker', on_click=lambda: marker.move(51.51, -0.09))\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 矢量图层\n", "\n", "Leaflet支持一系列[矢量图层](https://leafletjs.com/reference.html#:~:text=VideoOverlay-,Vector%20Layers,-Path),如圆形、多边形等。这些可以使用`generic_layer`方法添加。我们欢迎任何关于添加更多特定图层以简化使用的`pull`请求。" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "GenericLayer(leaflet=, id='265d0b7e-d54e-4ec7-929a-c606d8bf609c', name='circle', args=[(51.505, -0.09), {'color': 'red', 'radius': 300}])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09)).classes('h-32')\n", "m.generic_layer(name='circle', args=[m.center, {'color': 'red', 'radius': 300}])\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 禁用平移和缩放\n", "\n", "Leaflet中有多种选项可以[配置地图](https://leafletjs.com/reference.html#map)。这个演示禁用了平移和缩放控件。" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "options = {\n", " 'zoomControl': False,\n", " 'scrollWheelZoom': False,\n", " 'doubleClickZoom': False,\n", " 'boxZoom': False,\n", " 'keyboard': False,\n", " 'dragging': False,\n", "}\n", "ui.leaflet(center=(51.505, -0.09), options=options)\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 在地图上绘制\n", "\n", "您可以启用一个工具栏在地图上绘制。可以使用`draw_control`配置工具栏。这个演示通过点击地图添加标记和多边形。" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import events, ui\n", "\n", "def handle_draw(e: events.GenericEventArguments):\n", " if e.args['layerType'] == 'marker':\n", " m.marker(latlng=(e.args['layer']['_latlng']['lat'],\n", " e.args['layer']['_latlng']['lng']))\n", " if e.args['layerType'] == 'polygon':\n", " m.generic_layer(name='polygon', args=[e.args['layer']['_latlngs']])\n", "\n", "draw_control = {\n", " 'draw': {\n", " 'polygon': True,\n", " 'marker': True,\n", " 'circle': False,\n", " 'rectangle': False,\n", " 'polyline': False,\n", " 'circlemarker': False,\n", " },\n", " 'edit': False,\n", "}\n", "m = ui.leaflet(center=(51.505, -0.09), zoom=13, draw_control=draw_control)\n", "m.on('draw:created', handle_draw)\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 运行地图方法\n", "\n", "您可以使用`run_map_method`方法运行Leaflet地图对象的方法。这个演示展示了如何将地图适配到整个世界。" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09)).classes('h-32')\n", "ui.button('Fit world', on_click=lambda: m.run_map_method('fitWorld'))\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 运行地图图层\n", "\n", "您可以使用`run_layer_method`方法运行Leaflet图层对象的方法。这个演示展示了如何更改标记的透明度或更改其图标。" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from nicegui import ui\n", "\n", "m = ui.leaflet(center=(51.505, -0.09)).classes('h-32')\n", "marker = m.marker(latlng=m.center)\n", "ui.button('Hide', on_click=lambda: marker.run_method('setOpacity', 0.3))\n", "ui.button('Show', on_click=lambda: marker.run_method('setOpacity', 1.0))\n", "\n", "icon = 'L.icon({iconUrl: \"http://leafletjs.com/examples/custom-icons/leaf-green.png\"})'\n", "ui.button('Change icon', on_click=lambda: marker.run_method(':setIcon', icon))\n", "\n", "# ui.run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 等待初始化\n", "\n", "您可以使用`initialized`方法等待地图初始化。当您想在创建地图后立即运行像适应边界这样的方法时,这是必要的。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "from nicegui import ui\n", "\n", "m = ui.leaflet(zoom=5)\n", "central_park = m.generic_layer(name='polygon', args=[[\n", " (40.767809, -73.981249),\n", " (40.800273, -73.958291),\n", " (40.797011, -73.949683),\n", " (40.764704, -73.973741),\n", "]])\n", "await m.initialized()\n", "bounds = await central_park.run_method('getBounds')\n", "m.run_map_method('fitBounds', [[bounds['_southWest'], bounds['_northEast']]])\n", "\n", "ui.run()\n", "```" ] } ], "metadata": { "kernelspec": { "display_name": "py311", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.7" } }, "nbformat": 4, "nbformat_minor": 2 }