{
"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
}