Skip to main content

leaflet

图层和控件

Leaflet 是一个非常流行的开源 JavaScript 库,用于创建交互式地图。它提供了多种图层和控件来增强地图的功能。以下是一些常见的图层和控件:

图层

  1. 瓦片层(Tile Layer)

    • 用于加载和显示地图瓦片。
    • 示例:L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png')
  2. 矢量图层(Vector Layers)

    • 多边形(Polygon):用于绘制多边形区域。
      L.polygon([
      [51.509, -0.08],
      [51.503, -0.06],
      [51.51, -0.047]
      ]).addTo(map);
    • 折线(Polyline):用于绘制线条。
      L.polyline([
      [51.505, -0.09],
      [51.51, -0.1],
      [51.51, -0.12]
      ]).addTo(map);
    • 圆形(Circle):用于绘制圆形。
      L.circle([51.508, -0.11], { radius: 500 }).addTo(map);
    • 矩形(Rectangle):用于绘制矩形。
      L.rectangle([[51.49, -0.08], [51.5, -0.06]]).addTo(map);
  3. 图标层(Marker Layer)

    • 用于在地图上添加标记。
      L.marker([51.5, -0.09]).addTo(map);
  4. GeoJSON 图层

    • 用于加载和显示 GeoJSON 数据。
      L.geoJSON(geojsonData).addTo(map);

控件

  1. 缩放控件(Zoom Control)

    • 默认情况下,Leaflet 会在地图上添加缩放控件。
      L.control.zoom({ position: 'topright' }).addTo(map);
  2. 图层控件(Layers Control)

    • 用于切换不同的图层。
      var baseLayers = {
      "Mapbox": mapbox,
      "OpenStreetMap": osm
      };
      var overlays = {
      "Cities": cities
      };
      L.control.layers(baseLayers, overlays).addTo(map);
  3. 比例尺控件(Scale Control)

    • 显示地图的比例尺。
      L.control.scale().addTo(map);
  4. 自定义控件

    • 可以创建自定义控件。
      var customControl = L.Control.extend({
      options: {
      position: 'topright'
      },
      onAdd: function (map) {
      var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');
      container.innerHTML = 'Hello';
      return container;
      }
      });
      map.addControl(new customControl());

这些图层和控件可以组合使用,以创建功能丰富的交互式地图。

Panes

在 Leaflet 中,Panes 是一个用于控制图层渲染顺序的机制。每个图层都被渲染在一个特定的 pane 中,panes 是 HTML 元素,通常是 <div> 元素。通过使用 panes,你可以更精细地控制图层的渲染顺序和样式。

以下是如何在 Leaflet 中使用 panes 的示例:

  1. 首先,创建一个 Leaflet 地图实例,并设置初始视图:

    import L from 'leaflet';

    const map = L.map('map').setView([51.505, -0.09], 13);

    // 添加 OpenStreetMap 图层
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
  2. 你可以使用 map.createPane 方法来创建自定义 pane,并设置其样式。例如:

    // 创建自定义 pane
    const customPane = map.createPane('customPane');
    customPane.style.zIndex = 650; // 设置 z-index
    customPane.style.pointerEvents = 'none'; // 禁用鼠标事件
  3. 将图层添加到自定义 Pane。你可以在添加图层时指定要使用的 pane。例如:

    // 创建一个自定义图层,并将其添加到自定义 pane
    const customLayer = L.circle([51.505, -0.09], {
    color: 'red',
    radius: 200,
    pane: 'customPane'
    }).addTo(map);

内置 Panes

Leaflet 提供了一些内置的 panes,你可以直接使用它们:

  • mapPane:地图的主 pane,所有其他 panes 都在其上。
  • tilePane:瓦片图层的 pane。
  • overlayPane:覆盖物(如多边形、折线等)的 pane。
  • shadowPane:阴影的 pane。
  • markerPane:标记的 pane。
  • tooltipPane:工具提示的 pane。
  • popupPane:弹出窗口的 pane。

你可以在添加图层时指定要使用的内置 pane。例如:

// 将图层添加到 overlayPane
const overlayLayer = L.circle([51.505, -0.09], {
color: 'blue',
radius: 100,
pane: 'overlayPane'
}).addTo(map);

center

在Leaflet中,center参数用于设置地图的中心点。你可以在初始化地图时通过setView方法来设置中心点和缩放级别,也可以在地图初始化后动态设置中心点。center参数通常是一个包含纬度和经度的数组。如果你使用的是React和react-leaflet,可以通过MapContainer组件的center属性来设置中心点。

以下是一个基本示例,展示如何在Leaflet中设置地图的中心点:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map Center</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图,并设置中心点和缩放级别
var map = L.map('map').setView([39.9042, 116.4074], 10); // 北京的经纬度
</script>
</body>
</html>

在这个示例中,setView方法的第一个参数是一个包含纬度和经度的数组[39.9042, 116.4074],表示地图的中心点是北京。第二个参数是缩放级别,这里设置为10

动态设置中心点

你也可以在地图初始化后动态设置中心点,使用setView方法:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map Center</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图,并设置初始中心点和缩放级别
var map = L.map('map').setView([39.9042, 116.4074], 10); // 北京的经纬度

// 动态设置新的中心点
function setNewCenter(lat, lng) {
map.setView([lat, lng], map.getZoom());
}

// 示例:设置新的中心点为上海
setTimeout(() => {
setNewCenter(31.2304, 121.4737); // 上海的经纬度
}, 3000); // 3秒后设置新的中心点
</script>
</body>
</html>

在这个示例中,地图初始化时的中心点是北京。3秒后,中心点被动态设置为上海。

使用React-Leaflet设置中心点

如果你使用的是React和react-leaflet,你可以通过MapContainer组件的center属性来设置地图的中心点:

import React from 'react';
import { MapContainer, TileLayer } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';

const MyMap = () => {
return (
<MapContainer center={[39.9042, 116.4074]} zoom={10} style={{ height: '100vh', width: '100%' }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
</MapContainer>
);
};

export default MyMap;

在这个示例中,MapContainer组件的center属性被设置为[39.9042, 116.4074],表示地图的中心点是北京。

GeoJSON

Leaflet 是一个开源的 JavaScript 库,用于构建交互式地图。L.GeoJSON 是 Leaflet 中的一个类,用于处理和显示 GeoJSON 数据。GeoJSON 是一种用于表示地理数据的格式,支持点、线、多边形等几何类型。

以下是如何使用 L.GeoJSON 在 Leaflet 地图上显示 GeoJSON 数据的示例:

  1. 首先,创建一个 Leaflet 地图实例,并设置初始视图:

    import L from 'leaflet';

    const map = L.map('map').setView([51.505, -0.09], 13);

    // 添加 OpenStreetMap 图层
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
  2. 你可以使用 L.GeoJSON 类来添加和显示 GeoJSON 数据。以下是一个示例 GeoJSON 对象:

    const geojsonFeature = {
    "type": "Feature",
    "geometry": {
    "type": "Point",
    "coordinates": [-0.09, 51.505]
    },
    "properties": {
    "name": "A point",
    "popupContent": "This is a point!"
    }
    };

    // 创建 GeoJSON 图层并添加到地图
    L.geoJSON(geojsonFeature).addTo(map);
  3. 你可以通过传递选项对象来自定义 GeoJSON 图层的样式和交互。例如:

    const geojsonFeature = {
    "type": "Feature",
    "geometry": {
    "type": "Point",
    "coordinates": [-0.09, 51.505]
    },
    "properties": {
    "name": "A point",
    "popupContent": "This is a point!"
    }
    };

    // 自定义样式
    const geojsonLayer = L.geoJSON(geojsonFeature, {
    pointToLayer: function (feature, latlng) {
    return L.circleMarker(latlng, {
    radius: 8,
    fillColor: "#ff7800",
    color: "#000",
    weight: 1,
    opacity: 1,
    fillOpacity: 0.8
    });
    },
    onEachFeature: function (feature, layer) {
    if (feature.properties && feature.properties.popupContent) {
    layer.bindPopup(feature.properties.popupContent);
    }
    }
    }).addTo(map);

GridLayer

Leaflet 是一个开源的 JavaScript 库,用于构建交互式地图。GridLayer 是 Leaflet 中的一个基础类,用于创建基于网格的图层。GridLayer 通常用于实现瓦片图层(如 TileLayer),但你也可以扩展它来创建自定义的网格图层。

你可以通过扩展 L.GridLayer 来创建自定义的网格图层。你需要实现 createTile 方法,该方法用于创建和返回每个瓦片的 DOM 元素。

import L from 'leaflet';

const MyGridLayer = L.GridLayer.extend({
createTile: function (coords) {
const tile = document.createElement('div');
tile.innerHTML = [coords.x, coords.y, coords.z].join(', ');
tile.style.outline = '1px solid red';
return tile;
}
});

// 创建地图实例
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加自定义网格图层到地图
const myGridLayer = new MyGridLayer();
myGridLayer.addTo(map);

GridLayer 提供了一些选项,可以在创建实例时进行配置。例如:

  • tileSize:瓦片的大小,默认为 256。
  • opacity:瓦片的透明度,默认为 1。
  • updateWhenIdle:是否在地图空闲时更新瓦片,默认为 true。
  • updateWhenZooming:是否在缩放时更新瓦片,默认为 true。
  • zIndex:图层的 z-index,默认为 1。

你可以在创建 GridLayer 实例时传递这些选项:

const myGridLayer = new MyGridLayer({
tileSize: 256,
opacity: 0.5,
updateWhenIdle: false,
updateWhenZooming: true,
zIndex: 2
});

TileLayer

在Leaflet中,TileLayer用于加载和显示瓦片图层。url参数指定了瓦片图层的URL模板。这个URL模板通常包含占位符,用于动态替换瓦片的坐标和缩放级别。你可以根据需要调整URL模板和其他选项来加载不同的瓦片图层。

源码:

export const TileLayer = GridLayer.extend({})

export function tileLayer(url, options) {
return new TileLayer(url, options);
}

所以,L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'}); 等同于 new TileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});

URL 模板占位符

常见的占位符包括:

  • {z}: 缩放级别
  • {x}: 瓦片的x坐标
  • {y}: 瓦片的y坐标
  • {s}: 子域名(如果有)

以下是一个基本示例,展示如何在Leaflet中使用TileLayer并指定URL模板:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with TileLayer URL</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加瓦片图层
var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
subdomains: ['a', 'b', 'c'], // 指定子域名
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
</body>
</html>

在这个示例中,url参数被设置为https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png,并且使用了subdomains选项来指定子域名。

使用腾讯地图的示例

如果你想在Leaflet中使用腾讯地图,可以参考以下代码:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Tencent Map</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加腾讯地图瓦片图层
var tencentLayer = L.tileLayer('https://rt{0-3}.map.gtimg.com/tile?z={z}&x={x}&y={y}&styleid=7', {
subdomains: ['0', '1', '2', '3'], // 指定子域名
attribution: '&copy; <a href="http://map.qq.com/">Tencent Maps</a>'
}).addTo(map);
</script>
</body>
</html>

在这个示例中,url参数被设置为https://rt{0-3}.map.gtimg.com/tile?z={z}&x={x}&y={y}&styleid=7,并且使用了subdomains选项来指定子域名。

使用Mapbox的示例

如果你想在Leaflet中使用Mapbox,可以参考以下代码:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Mapbox</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加Mapbox瓦片图层
var mapboxLayer = L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=YOUR_MAPBOX_ACCESS_TOKEN', {
attribution: '&copy; <a href="https://www.mapbox.com/">Mapbox</a>',
tileSize: 512,
zoomOffset: -1
}).addTo(map);
</script>
</body>
</html>

在这个示例中,url参数被设置为https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=YOUR_MAPBOX_ACCESS_TOKEN,你需要替换YOUR_MAPBOX_ACCESS_TOKEN为你自己的Mapbox访问令牌。

styleid

在Leaflet中,styleid通常是用于指定特定地图样式的参数。这在使用某些地图服务(如腾讯地图或Mapbox)时特别有用,因为这些服务提供了多种不同的地图样式。通过调整styleid,你可以轻松切换不同的地图外观,以满足你的应用需求。

腾讯地图提供了多种不同的地图样式,你可以通过styleid参数来指定你想要的样式。以下是一些常见的styleid值:

  • 0: 街道地图
  • 1: 卫星地图
  • 2: 混合地图(街道和卫星)
  • 3: 地形图
  • 4: 灰色地图
  • 5: 蓝色地图
  • 6: 暗色地图
  • 7: 彩色地图

使用腾讯地图的示例

腾讯地图提供了多种不同的地图样式,你可以通过styleid参数来指定你想要的样式。以下是一个示例,展示如何在Leaflet中使用腾讯地图并指定styleid

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Tencent Map and StyleID</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加腾讯地图瓦片图层,并使用styleid指定地图样式
var tencentLayer = L.tileLayer('https://rt{0-3}.map.gtimg.com/tile?z={z}&x={x}&y={y}&styleid=7', {
subdomains: ['0', '1', '2', '3'], // 指定子域名
attribution: '&copy; <a href="http://map.qq.com/">Tencent Maps</a>'
}).addTo(map);
</script>
</body>
</html>

在这个示例中,styleid=7指定了腾讯地图的一种特定样式。你可以根据需要更改styleid的值来使用不同的地图样式。

使用Mapbox的示例

如果你使用的是Mapbox,你可以通过URL中的样式ID来指定地图样式。以下是一个示例,展示如何在Leaflet中使用Mapbox并指定样式:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Mapbox and StyleID</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加Mapbox瓦片图层,并使用样式ID指定地图样式
var mapboxLayer = L.tileLayer('https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/{z}/{x}/{y}?access_token=YOUR_MAPBOX_ACCESS_TOKEN', {
attribution: '&copy; <a href="https://www.mapbox.com/">Mapbox</a>',
tileSize: 512,
zoomOffset: -1
}).addTo(map);
</script>
</body>
</html>

在这个示例中,mapbox/satellite-v9是Mapbox的样式ID,指定了卫星地图样式。你可以替换为其他样式ID,如mapbox/streets-v11来使用不同的地图样式。

subdomains

在Leaflet中,subdomains选项用于指定瓦片图层的子域名。这对于负载均衡和提高瓦片加载速度非常有用,因为浏览器通常对同一域名的并发请求数量有限制。

以下是一个示例,展示如何在Leaflet中使用subdomains选项:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Subdomains</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加瓦片图层,并使用子域名
var tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
subdomains: ['a', 'b', 'c'], // 指定子域名
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
</script>
</body>
</html>

在这个示例中,subdomains选项被设置为['a', 'b', 'c'],这意味着瓦片请求将轮流使用a.tile.openstreetmap.orgb.tile.openstreetmap.orgc.tile.openstreetmap.org这三个子域名。

使用腾讯地图的示例

如果你想在Leaflet中使用腾讯地图,并指定子域名,可以参考以下代码:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet with Tencent Map and Subdomains</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
var map = L.map('map').setView([39.9042, 116.4074], 10); // 设置中心点和缩放级别

// 添加腾讯地图瓦片图层,并使用子域名
var tencentLayer = L.tileLayer('https://rt{0-3}.map.gtimg.com/tile?z={z}&x={x}&y={y}&styleid=7', {
subdomains: ['0', '1', '2', '3'], // 指定子域名
attribution: '&copy; <a href="http://map.qq.com/">Tencent Maps</a>'
}).addTo(map);
</script>
</body>
</html>

在这个示例中,subdomains选项被设置为['0', '1', '2', '3'],这意味着瓦片请求将轮流使用rt0.map.gtimg.comrt1.map.gtimg.comrt2.map.gtimg.comrt3.map.gtimg.com这四个子域名。

通过使用subdomains选项,你可以有效地分散瓦片请求,提升地图加载性能。

L.FeatureGroup

L.FeatureGroup 是 Leaflet 中的一个类,用于将多个图层(如多边形、折线、标记等)组合在一起,作为一个整体进行操作。你可以将多个图层添加到一个 L.FeatureGroup 中,然后对这个组进行操作,例如添加到地图、绑定事件、设置样式等。

L.polyline

L.polyline 是 Leaflet 库中用于绘制折线的类。它提供了多种方法来操作和管理折线。以下是一些常用的方法,包括你提到的 setLatLngs

  1. setLatLngs(latlngs):

    • 设置折线的坐标点。
    • 参数:latlngs 是一个包含坐标点的数组。
  2. getLatLngs():

    • 获取折线的所有坐标点。
    • 返回值:一个包含坐标点的数组。
  3. addLatLng(latlng):

    • 向折线添加一个新的坐标点。
    • 参数:latlng 是一个坐标点。
  4. setStyle(style):

    • 设置折线的样式。
    • 参数:style 是一个包含样式选项的对象。
  5. bringToFront():

    • 将折线置于地图的最前面。
  6. bringToBack():

    • 将折线置于地图的最后面。
  7. redraw():

    • 重新绘制折线。
  8. toGeoJSON():

    • 将折线转换为 GeoJSON 对象。
    • 返回值:一个 GeoJSON 对象。
  9. getBounds():

    • 获取折线的边界框。
    • 返回值:一个 LatLngBounds 对象。
  10. remove():

    • 从地图上移除折线。
  11. on(event, callback):

    • 为折线绑定一个事件监听器。
    • 参数:event 是事件名称,callback 是事件触发时的回调函数。
  12. off(event, callback):

    • 移除折线的事件监听器。
    • 参数:event 是事件名称,callback 是要移除的回调函数。
  13. bindPopup(content, options):

    • 为折线绑定一个弹出框。
    • 参数:content 是弹出框的内容,options 是弹出框的选项。
  14. unbindPopup():

    • 解除折线的弹出框绑定。
  15. openPopup(latlng):

    • 在指定位置打开折线的弹出框。
    • 参数:latlng 是弹出框的位置。
  16. closePopup():

    • 关闭折线的弹出框。

这些方法使得 L.polyline 非常灵活,可以方便地进行各种操作和管理。你可以根据需要使用这些方法来操作折线。

L.PM.Utils.findDeepMarkerIndex

L.PM.Utils.findDeepMarkerIndex 是 Leaflet.PM(GeoMan)库中的一个实用函数,用于在嵌套的多边形或多折线结构中查找特定标记(marker)的索引。这个函数在处理复杂的几何图形时非常有用,特别是当你需要知道某个标记在多边形或多折线中的具体位置时。

以下是 L.PM.Utils.findDeepMarkerIndex 的作用和使用示例:

作用

L.PM.Utils.findDeepMarkerIndex 用于在嵌套的数组结构中查找特定标记的索引。它会遍历整个数组结构,直到找到匹配的标记,并返回其索引。

使用示例

假设你有一个多边形,并且你想找到其中某个标记的索引:

// 初始化地图
var map = L.map('map').setView([51.505, -0.09], 13);

// 添加底图图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);

// 初始化 GeoMan
map.pm.addControls({
position: 'topleft',
drawPolygon: true,
drawMarker: false,
drawPolyline: false,
drawCircle: false,
drawCircleMarker: false,
drawRectangle: false,
editMode: false,
dragMode: false,
cutPolygon: false,
removalMode: false
});

// 创建一个多边形
var polygon = L.polygon([
[51.509, -0.08],
[51.503, -0.06],
[51.51, -0.047]
]).addTo(map);

// 获取多边形的所有标记
var markers = polygon.getLatLngs()[0];

// 假设我们要查找的标记是第一个标记
var targetMarker = markers[0];

// 使用 findDeepMarkerIndex 查找标记的索引
var index = L.PM.Utils.findDeepMarkerIndex(markers, targetMarker);

console.log('Marker Index:', index); // 输出:Marker Index: 0

参数

  • markers:一个包含标记的数组,可以是嵌套的数组结构。
  • targetMarker:你要查找的目标标记。

返回值

  • 返回目标标记在数组中的索引。如果没有找到,则返回 -1

这个函数在处理复杂的几何图形时非常有用,特别是当你需要知道某个标记在多边形或多折线中的具体位置时。希望这个解释和示例能帮到你!如果有其他问题,请随时问我。

L.DomUtil

L.DomUtil 是 Leaflet 提供的一个实用工具集,用于操作 DOM 元素。以下是 L.DomUtil 提供的一些常用方法及其简要说明:

常用方法

  1. L.DomUtil.create(tagName, className, container)

    • 创建一个指定标签名和类名的 DOM 元素,并可选择性地将其添加到指定的容器中。
    • 参数:
      • tagName (string): 要创建的元素的标签名。
      • className (string): 要添加到元素的类名。
      • container (HTMLElement): 可选,要将新元素添加到的父容器。
    var div = L.DomUtil.create('div', 'my-class', parentElement);
  2. L.DomUtil.get(id)

    • 根据 ID 获取 DOM 元素。
    • 参数:
      • id (string): 元素的 ID。
    var element = L.DomUtil.get('my-element-id');
  3. L.DomUtil.getStyle(el, style)

    • 获取指定元素的指定样式属性的值。
    • 参数:
      • el (HTMLElement): 要获取样式的元素。
      • style (string): 样式属性名。
    var opacity = L.DomUtil.getStyle(element, 'opacity');
  4. L.DomUtil.addClass(el, name)

    • 为指定元素添加类名。
    • 参数:
      • el (HTMLElement): 要添加类名的元素。
      • name (string): 要添加的类名。
    L.DomUtil.addClass(element, 'new-class');
  5. L.DomUtil.removeClass(el, name)

    • 从指定元素中移除类名。
    • 参数:
      • el (HTMLElement): 要移除类名的元素。
      • name (string): 要移除的类名。
    L.DomUtil.removeClass(element, 'old-class');
  6. L.DomUtil.hasClass(el, name)

    • 检查指定元素是否具有指定的类名。
    • 参数:
      • el (HTMLElement): 要检查的元素。
      • name (string): 要检查的类名。
    var hasClass = L.DomUtil.hasClass(element, 'my-class');
  7. L.DomUtil.setOpacity(el, opacity)

    • 设置指定元素的透明度。
    • 参数:
      • el (HTMLElement): 要设置透明度的元素。
      • opacity (number): 透明度值(0 到 1 之间)。
    L.DomUtil.setOpacity(element, 0.5);
  8. L.DomUtil.testProp(props)

    • 检查浏览器是否支持指定的 CSS 属性。
    • 参数:
      • props (Array): 要检查的 CSS 属性名数组。
    var supportedProp = L.DomUtil.testProp(['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
  9. L.DomUtil.setTransform(el, offset, scale)

    • 设置元素的 CSS 变换属性。
    • 参数:
      • el (HTMLElement): 要设置变换的元素。
      • offset (L.Point): 偏移量。
      • scale (number): 缩放比例。
    L.DomUtil.setTransform(element, L.point(100, 100), 2);
  10. L.DomUtil.setPosition(el, point)

    • 设置元素的位置。
    • 参数:
      • el (HTMLElement): 要设置位置的元素。
      • point (L.Point): 位置点。
    L.DomUtil.setPosition(element, L.point(100, 100));

示例

以下是一个使用 L.DomUtil 创建和操作 DOM 元素的示例:

// 创建一个新的 div 元素,并添加到地图容器中
var mapContainer = document.getElementById('map');
var customDiv = L.DomUtil.create('div', 'custom-control', mapContainer);

// 设置样式和事件
customDiv.style.backgroundColor = 'white';
customDiv.style.width = '100px';
customDiv.style.height = '30px';
customDiv.style.cursor = 'pointer';

customDiv.innerHTML = 'Click me';
customDiv.onclick = function() {
alert('Custom control clicked!');
};

// 添加类名
L.DomUtil.addClass(customDiv, 'additional-class');

// 检查类名
if (L.DomUtil.hasClass(customDiv, 'additional-class')) {
console.log('Class added successfully');
}

// 设置透明度
L.DomUtil.setOpacity(customDiv, 0.8);

这些方法可以帮助你更方便地操作和管理 Leaflet 地图中的 DOM 元素。更多详细信息可以参考 Leaflet 官方文档

Leaflet 控件

Leaflet 是一个开源的 JavaScript 库,用于创建互动地图。Leaflet 提供了多种控件(Control)来增强地图的功能。以下是一些常见的 Leaflet 控件及其用法:

1. 缩放控件(Zoom Control)

默认情况下,Leaflet 会在地图的右下角添加一个缩放控件。你可以通过以下代码自定义其位置:

var map = L.map('map', {
zoomControl: false // 先禁用默认的缩放控件
}).setView([51.505, -0.09], 13);

L.control.zoom({
position: 'topright' // 设置缩放控件的位置
}).addTo(map);

2. 图层控件(Layers Control)

图层控件允许用户在不同的地图图层之间切换:

var streets = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
id: 'mapbox/streets-v11'
});

var satellite = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
id: 'mapbox/satellite-v9'
});

var baseMaps = {
"Streets": streets,
"Satellite": satellite
};

L.control.layers(baseMaps).addTo(map);

3. 比例尺控件(Scale Control)

比例尺控件显示地图的比例尺:

L.control.scale({
position: 'bottomleft', // 设置比例尺控件的位置
metric: true, // 使用公制单位
imperial: false // 不使用英制单位
}).addTo(map);

4. 自定义控件

你还可以创建自定义控件。例如,一个简单的按钮控件:

var customControl = L.Control.extend({
options: {
position: 'topright' // 设置控件的位置
},

onAdd: function (map) {
var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom');

container.style.backgroundColor = 'white';
container.style.width = '30px';
container.style.height = '30px';

container.onclick = function(){
alert('Button clicked!');
}

return container;
}
});

map.addControl(new customControl());

这些是一些常见的 Leaflet 控件及其用法。你可以根据需要进行自定义和扩展。需要更多信息可以参考 Leaflet 官方文档

5. 地图数据来源和版权信息的控件

在 Leaflet 中,attributionControl 是一个用于显示地图数据来源和版权信息的控件。它通常位于地图的右下角。通过配置 attributionControl,你可以自定义显示的文本和样式。

以下是一个简单的示例,展示如何在 Leaflet 地图中自定义 attributionControl

// 创建地图实例
var map = L.map('map', {
attributionControl: true // 默认情况下是启用的
}).setView([51.505, -0.09], 13);

// 添加 TileLayer
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// 自定义 attributionControl 的位置和内容
map.attributionControl.setPrefix('My Custom Map');
map.attributionControl.setPosition('topright');

主要方法和属性:

  • setPrefix(prefix): 设置 attribution 控件的前缀文本。例如,你可以将其设置为你自己的版权信息或公司名称。
  • setPosition(position): 设置控件的位置。可选值包括 'topleft', 'topright', 'bottomleft', 'bottomright'。默认情况下,attribution 控件位于地图的右下角 ('bottomright')。

map.whenReady

在 Leaflet 中,map.whenReady 是一个方法,用于在地图及其所有图层完全加载并准备好交互时执行回调函数。这对于确保在地图完全初始化后执行某些操作非常有用。

下面是一个示例,展示如何使用 map.whenReady 方法:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Map Example</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
#map {
height: 400px;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 创建地图实例并设置初始视图
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加 OpenStreetMap 图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// 使用 whenReady 方法
map.whenReady(() => {
console.log('Map is fully loaded and ready.');
// 在地图完全加载后执行的操作
L.marker([51.5, -0.09]).addTo(map)
.bindPopup('A pretty CSS3 popup.<br> Easily customizable.')
.openPopup();
});
</script>
</body>
</html>

在这个示例中:

  1. 创建了一个 Leaflet 地图实例,并设置了初始视图。
  2. 添加了一个 OpenStreetMap 图层。
  3. 使用 map.whenReady 方法,在地图及其所有图层完全加载并准备好交互时执行回调函数。
  4. 在回调函数中,添加了一个标记,并绑定了一个弹出窗口。

通过这种方式,你可以确保在地图完全初始化后执行特定的操作。

类型声明

leaflet的类型声明统一在@types/leaflet

map.fitBounds

fitBounds 方法用于调整地图视图,使其适合指定的地理边界(bounds)。它接受两个参数:一个 LatLngBounds 对象和一个可选的 boundsOptions 对象。

map.fitBounds(bounds, boundsOptions);

bounds 是一个数组,表示要适应的地理边界的西南和东北角。

const bounds = [
[51.49, -0.08], // 西南角
[51.5, -0.06] // 东北角
];

boundsOptions 是一个对象,可以包含以下属性:

  • paddingTopLeft: Point - 在地图视图的左上角添加填充。
  • paddingBottomRight: Point - 在地图视图的右下角添加填充。
  • padding: Point - 在地图视图的四周添加填充。
  • maxZoom: number - 设置最大缩放级别。
  • animate: boolean - 是否启用动画(默认为 true)。
  • duration: number - 动画持续时间(以秒为单位)。
  • easeLinearity: number - 动画的线性度(默认为 0.25)。
  • noMoveStart: boolean - 如果为 true,则不会触发 movestart 事件。

以下是一个使用 fitBounds 方法的示例,展示了如何在 React 中使用 react-leaflet 调整地图视图以适应指定的边界:

import React, { useEffect, useRef } from 'react';
import { MapContainer, TileLayer, Rectangle, useMap } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';

const bounds = [
[51.49, -0.08], // Southwest corner
[51.5, -0.06] // Northeast corner
];

const FitBoundsComponent = () => {
const map = useMap();

useEffect(() => {
map.fitBounds(bounds, {
padding: [50, 50], // Optional padding around the bounds
maxZoom: 15, // Optional maximum zoom level
animate: true,
duration: 1.0
});
}, [map]);

return null;
};

const MapComponent = () => {
return (
<MapContainer center={[51.505, -0.09]} zoom={13} style={{ height: "100vh", width: "100%" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
<Rectangle bounds={bounds} />
<FitBoundsComponent />
</MapContainer>
);
};

export default MapComponent;

map.zoomIn

在 Leaflet 中,map.zoomIn 方法用于放大地图视图。这个方法可以接受两个可选参数。

map.zoomIn(delta?: number, options?: ZoomPanOptions): this;
  1. delta(可选):放大的级别,默认为 1。如果你希望一次放大多个级别,可以传递一个数字。例如,传递 2 表示放大两个级别。

  2. options(可选):一个包含动画和缩放选项的对象。ZoomPanOptions 类型的对象可以包含以下属性:

    • animate:布尔值,是否启用动画效果。
    • duration:动画持续时间(以秒为单位)。
    • easeLinearity:动画的线性度,默认为 0.25。
    • noMoveStart:布尔值,是否在缩放时触发 movestart 事件。

以下是一些使用 map.zoomIn 方法的示例:

// 简单放大一个级别
map.zoomIn();
// 放大两个级别
map.zoomIn(2);
// 带动画选项的放大
map.zoomIn(1, {
animate: true,
duration: 0.5
});

map.zoomOut

在 Leaflet 中,map.zoomOut 方法用于缩小地图视图。这个方法可以接受两个可选参数。

map.zoomOut(delta?: number, options?: ZoomPanOptions): this;
  1. delta(可选):缩小的级别,默认为 1。如果你希望一次缩小多个级别,可以传递一个数字。例如,传递 2 表示缩小两个级别。

  2. options(可选):一个包含动画和缩放选项的对象。ZoomPanOptions 类型的对象可以包含以下属性:

    • animate:布尔值,是否启用动画效果。
    • duration:动画持续时间(以秒为单位)。
    • easeLinearity:动画的线性度,默认为 0.25。
    • noMoveStart:布尔值,是否在缩放时触发 movestart 事件。

以下是一些使用 map.zoomOut 方法的示例:

// 简单缩小一个级别
map.zoomOut();
// 缩小两个级别
map.zoomOut(2);
// 带动画选项的缩小
map.zoomOut(1, {
animate: true,
duration: 0.5
});

map.setZoom

将地图缩放到指定级别。例如:

map.setZoom(10);

map.flyTo

平滑地缩放和移动地图到指定位置和缩放级别。例如:

map.flyTo([51.505, -0.09], 14);

map.setMinZoom

动态设置 Leaflet 地图的最小缩放级别。

map.setMinZoom(6);

map.setMaxZoom

动态设置 Leaflet 地图的最大缩放级别。

map.setMaxZoom(18);

map.locate

在 Leaflet 中,map.locate 方法用于请求用户的地理位置。这个方法会触发 locationfound 事件(如果定位成功)或 locationerror 事件(如果定位失败)。你可以使用这些事件来处理定位结果并在地图上显示用户的位置。

以下是如何使用 map.locate 方法在 Leaflet 地图上显示用户位置的示例:

import L from 'leaflet';

// 创建地图实例并设置初始视图
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加 OpenStreetMap 图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// 处理 locationfound 事件
map.on('locationfound', (e) => {
const radius = e.accuracy / 2; // e.accuracy 属性表示用户位置的精度(以米为单位)。这个值是一个半径,表示用户位置的误差范围。例如,如果 e.accuracy 的值是 50,那么用户的位置在 50 米的半径范围内是准确的。

// 添加用户位置的圆形标记
L.circle(e.latlng, radius).addTo(map);

// 添加用户位置的标记
L.marker(e.latlng).addTo(map)
.bindPopup(`You are within ${radius} meters from this point`).openPopup();
});

// 处理 locationerror 事件
map.on('locationerror', (e) => {
alert(e.message);
});

// 调用 locate 方法获取用户位置
map.locate({ setView: true, maxZoom: 16 });
  1. 创建地图实例:使用 L.map 创建一个地图实例,并设置初始视图。
  2. 添加图层:使用 L.tileLayer 添加 OpenStreetMap 图层到地图。
  3. 处理 locationfound 事件:使用 map.on('locationfound', callback) 监听 locationfound 事件。在回调函数中,你可以获取用户的位置并在地图上显示。
  4. 处理 locationerror 事件:使用 map.on('locationerror', callback) 监听 locationerror 事件,以处理地理定位失败的情况。
  5. 调用 map.locate 方法:使用 map.locate 方法请求用户位置。你可以传递选项对象来配置定位行为,例如 setView: truemaxZoom: 16

map.locate 方法接受一个选项对象,你可以使用这些选项来配置定位行为:

  • watch:布尔值,是否持续监视位置变化。
  • setView:布尔值,是否将地图视图设置为用户位置。
  • maxZoom:最大缩放级别。
  • timeout:定位请求的超时时间(以毫秒为单位)。
  • maximumAge:允许返回的缓存位置的最大年龄(以毫秒为单位)。
  • enableHighAccuracy:布尔值,是否启用高精度定位。
map.locate({
watch: true,
setView: true,
maxZoom: 16,
timeout: 10000,
maximumAge: 0,
enableHighAccuracy: true
});

map.invalidateSize

在 Leaflet 中,map.invalidateSize() 方法用于通知地图容器的大小已发生变化,并强制地图重新计算其尺寸。这在调整地图容器的大小(例如通过 CSS 或 JavaScript)后非常有用,确保地图正确地填充其容器。

以下是一个完整的示例,展示如何在 Flexbox 布局中实现左侧是 Leaflet 渲染的瓦片地图,右侧是可收起的面板,并确保在右侧面板收起后左侧地图能够铺满屏幕:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Leaflet Flexbox Layout</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
.container {
display: flex;
height: 100vh;
}

.left-panel {
flex: 1;
position: relative;
}

.right-panel {
width: 300px;
background-color: #d0d0d0;
padding: 20px;
transition: width 0.3s, padding 0.3s;
}

.right-panel.collapsed {
width: 0;
padding: 0;
overflow: hidden;
}

#map {
width: 100%;
height: 100%;
}

.toggle-button {
position: absolute;
top: 10px;
right: 10px;
z-index: 1000;
}
</style>
</head>
<body>
<div class="container">
<div class="left-panel">
<button class="toggle-button" id="toggle-button">收起</button>
<div id="map"></div>
</div>
<div class="right-panel" id="right-panel">
右侧内容
</div>
</div>

<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// 初始化地图
const map = L.map('map').setView([51.505, -0.09], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

// 切换右侧面板的显示和隐藏
document.getElementById('toggle-button').addEventListener('click', function() {
const rightPanel = document.getElementById('right-panel');
rightPanel.classList.toggle('collapsed');
setTimeout(() => {
map.invalidateSize(); // 重新调整地图大小
}, 300); // 与 CSS 过渡时间匹配
});
</script>
</body>
</html>

解释:

  1. HTML 结构

    • container 是一个包含两个子元素的父容器:left-panelright-panel
    • left-panel 内部包含一个按钮,用于控制右侧面板的收起和展开,以及一个用于渲染地图的 div 元素。
    • right-panel 是可收起的面板,包含一些内容。
  2. CSS 样式

    • container 使用 display: flex 来创建一个 Flexbox 容器。
    • left-panel 使用 flex: 1 来占据剩余的空间,并设置 position: relative 以便定位按钮。
    • right-panel 设置了固定的宽度 300px,并且在添加 collapsed 类时将宽度设置为 0,并隐藏其内容。
    • map 设置了 width: 100%height: 100%,以确保地图铺满 left-panel
  3. JavaScript

    • 初始化 Leaflet 地图,并将其添加到 map 元素中。
    • 通过点击按钮,切换 right-panelcollapsed 类,从而控制其显示和隐藏。
    • 在右侧面板收起或展开后,调用 map.invalidateSize() 方法重新调整地图大小,以确保地图铺满 left-panel

这样,当你点击 "收起" 按钮时,右侧面板将收起,左侧地图将铺满整个容器。再次点击按钮,右侧面板将展开,恢复到原来的布局。地图会根据容器的大小自动调整。

map.setView

在 Leaflet 中,map.setView 方法用于设置地图的视图中心和缩放级别。这个方法可以让你动态地调整地图的中心位置和缩放级别,非常适合在用户交互或数据更新时使用。

map.setView 方法接受两个主要参数:

  1. 中心位置:一个包含纬度和经度的数组或 LatLng 对象。
  2. 缩放级别:一个整数,表示地图的缩放级别。

此外,还可以传递一个可选的选项对象来控制动画效果等。

以下是一个使用 map.setView 方法的示例,展示如何在 React 中使用 react-leaflet 动态调整地图的视图:

import React, { useRef } from 'react';
import { MapContainer, TileLayer, useMap } from 'react-leaflet';
import 'leaflet/dist/leaflet.css';

const SetViewComponent = ({ center, zoom }) => {
const map = useMap();

React.useEffect(() => {
map.setView(center, zoom, {
animate: true,
duration: 1.0
});
}, [map, center, zoom]);

return null;
};

const MapComponent = () => {
const initialCenter = [51.505, -0.09];
const initialZoom = 13;

const newCenter = [48.8566, 2.3522]; // Paris coordinates
const newZoom = 12;

const mapRef = useRef();

const handleButtonClick = () => {
mapRef.current.setView(newCenter, newZoom, {
animate: true,
duration: 1.0
});
};

return (
<div>
<button onClick={handleButtonClick}>Go to Paris</button>
<MapContainer
center={initialCenter}
zoom={initialZoom}
style={{ height: "100vh", width: "100%" }}
whenCreated={mapInstance => { mapRef.current = mapInstance; }}
>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
/>
</MapContainer>
</div>
);
};

export default MapComponent;

解释:

  1. HTML 结构

    • MapContainerreact-leaflet 提供的组件,用于创建一个 Leaflet 地图容器。
    • TileLayerreact-leaflet 提供的组件,用于加载瓦片图层。
    • SetViewComponent 是一个自定义组件,用于动态设置地图视图。
  2. CSS 样式

    • MapContainerstyle 属性设置了地图容器的高度和宽度,以确保地图铺满整个视口。
  3. JavaScript

    • 使用 useRef 钩子创建一个 mapRef 引用,用于存储地图实例。
    • MapContainerwhenCreated 属性中,将地图实例存储到 mapRef 中。
    • SetViewComponent 组件中,使用 useMap 钩子获取地图实例,并在 useEffect 钩子中调用 map.setView 方法来动态设置地图视图。
    • 在按钮的点击事件处理程序中,调用 mapRef.current.setView 方法来动态调整地图的中心位置和缩放级别。

setView 方法的选项

setView 方法可以接受一个可选的选项对象,以进一步控制视图调整的行为。常用选项包括:

  • animate:是否使用动画效果调整视图(默认为 false)。
  • duration:动画效果的持续时间(以秒为单位)。
  • easeLinearity:动画效果的线性度(默认为 0.25)。
  • noMoveStart:如果为 true,则不会触发 movestart 事件。

例如:

map.setView([48.8566, 2.3522], 12, {
animate: true,
duration: 1.0,
easeLinearity: 0.5,
noMoveStart: true
});

你可以根据需要调整这些选项,以适应你的具体需求。

map.getBounds

在 Leaflet 中,map.getBounds() 返回一个 LatLngBounds 对象,该对象表示地图的当前视图范围。LatLngBounds 对象有一个 toBBoxString() 方法,可以将边界框转换为一个逗号分隔的字符串,格式为 minLon,minLat,maxLon,maxLat

获取地图上的所有多边形

// 获取地图上的所有多边形
function getAllPolygons() {
const allPolygons = [];
map.eachLayer(layer => {
if (layer instanceof L.Polygon && !(layer instanceof L.Circle)) {
allPolygons.push(layer);
}
});
return allPolygons;
}

渲染大规模的 AOI

在 Leaflet 中渲染大规模的 AOI(Area of Interest)数据时,可能会遇到性能问题。为了提高渲染性能,可以采用以下几种方法:

  1. 简化几何图形:使用工具或库(如 Turf.js)来简化几何图形,减少顶点数量。
  2. 按需加载数据:使用瓦片服务或按需加载数据,只加载当前视图范围内的数据。
  3. 使用 WebGL:使用基于 WebGL 的渲染库(如 Mapbox GL JS)来提高渲染性能。
  4. 虚拟化:将数据分块处理,逐步加载和渲染。

以下是每种方法的详细说明和示例代码:

方法一:简化几何图形

使用 Turf.js 的 simplify 方法来简化几何图形,减少顶点数量。

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Simplify Geometry</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/@turf/turf"></script>
<script>
// 初始化地图
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加 OpenStreetMap 图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);

// 示例 AOI 数据(GeoJSON 格式)
const aoiData = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [
[
[-0.1, 51.5],
[-0.1, 51.6],
[0.1, 51.6],
[0.1, 51.5],
[-0.1, 51.5]
]
]
}
}
]
};

// 使用 Turf.js 简化几何图形
const simplifiedData = turf.simplify(aoiData, { tolerance: 0.01, highQuality: false });

// 渲染简化后的数据
L.geoJSON(simplifiedData).addTo(map);
</script>
</body>
</html>

方法二:按需加载数据

使用 Leaflet 的 L.TileLayerL.GeoJSON 结合按需加载数据。

<!DOCTYPE html>
<html>
<head>
<title>Leaflet On-Demand Loading</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script>
// 初始化地图
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加 OpenStreetMap 图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);

// 按需加载数据
function loadGeoJSON(bounds) {
// 示例:根据视图范围加载数据
const url = `https://example.com/geojson?bbox=${bounds.toBBoxString()}`;
fetch(url)
.then(response => response.json())
.then(data => {
L.geoJSON(data).addTo(map);
});
}

// 监听视图变化事件
map.on('moveend', () => {
const bounds = map.getBounds();
loadGeoJSON(bounds);
});

// 初始加载
loadGeoJSON(map.getBounds());
</script>
</body>
</html>

方法三:使用 WebGL

使用基于 WebGL 的渲染库(如 Mapbox GL JS)来提高渲染性能。

<!DOCTYPE html>
<html>
<head>
<title>Mapbox GL JS</title>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<link href="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.css" rel="stylesheet" />
<style>
body { margin: 0; padding: 0; }
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
</style>
</head>
<body>
<div id="map"></div>
<script src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"></script>
<script>
// 初始化 Mapbox GL JS 地图
mapboxgl.accessToken = 'your-access-token';
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/streets-v11',
center: [-0.09, 51.505],
zoom: 13
});

// 添加 GeoJSON 数据源
map.on('load', () => {
map.addSource('aoi', {
'type': 'geojson',
'data': 'https://example.com/large-aoi-data.geojson'
});

// 添加图层
map.addLayer({
'id': 'aoi-layer',
'type': 'fill',
'source': 'aoi',
'layout': {},
'paint': {
'fill-color': '#888888',
'fill-opacity': 0.4
}
});
});
</script>
</body>
</html>

方法四:虚拟化

将数据分块处理,逐步加载和渲染。

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Virtualization</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css" />
<style>
#map {
height: 100vh;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
<script>
// 初始化地图
const map = L.map('map').setView([51.505, -0.09], 13);

// 添加 OpenStreetMap 图层
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19
}).addTo(map);

// 示例 AOI 数据(GeoJSON 格式)
const aoiData = {
"type": "FeatureCollection",
"features": [
// 大量的多边形数据
]
};

// 分块处理数据
const chunkSize = 100; // 每次处理的特征数量
let currentIndex = 0;

function processChunk() {
const chunk = aoiData.features.slice(currentIndex, currentIndex + chunkSize);
if (chunk.length > 0) {
L.geoJSON({ type: 'FeatureCollection', features: chunk }).addTo(map);
currentIndex += chunkSize;
requestAnimationFrame(processChunk);
}
}

// 开始处理
processChunk();
</script>
</body>
</html>

通过这些方法,你可以有效地提高 Leaflet 渲染大规模 AOI 数据的性能。选择适合你项目需求的方法即可。