DengBlog
Picture of the author

MapLibre GL JS地图的使用

Mon Sep 02 2024
#MapLibre

MapLibre GL JS 是一个 TypeScript 库,它使用 WebGL 从浏览器中的矢量瓦片渲染交互式地图。

举个官网的栗子:

Blog

在react中使用对初始化地图进行简单封装:

1import maplibregl from 'maplibre-gl'
2import React, { useEffect, useState } from 'react'
3
4interface Props {
5  initStyle: string
6  onMapLoaded: (by: maplibregl.Map) => void
7}
8
9const Index: React.FC<Props> = ({ onMapLoaded, initStyle }) => {
10  const [mapLoading, setMapLoading] = useState(true)
11
12  useEffect(() => {
13    const map = new maplibregl.Map({
14      container: 'map', // container id
15      style: initStyle || 'https://demotiles.maplibre.org/style.json', // style URL
16      center: [0, 0], // starting position [lng, lat]
17      zoom: 1, // starting zoom
18    })
19
20    map.on('load', () => {
21      onMapLoaded(map)
22      setMapLoading(false)
23    })
24  }, [])
25
26  return (
27    <>
28      {mapLoading ? (
29        <div id="map" className="w-full h-full flex items-center justify-center">
30          Loading...
31        </div>
32      ) : (
33        <div id="map" className="w-full h-full"></div>
34      )}
35    </>
36  )
37}
38export default Index
39
一些常用的API
  • map.addLayer():将MapLibre 样式图层添加到地图的样式中。
1map.addLayer({
2  id: 'points-of-interest',
3  source: {
4    type: 'vector',
5    url: 'https://demotiles.maplibre.org/tiles/tiles.json'
6  },
7  'source-layer': 'poi_label',
8  type: 'circle',
9  paint: {
10    // MapLibre Style Specification paint properties
11  },
12  layout: {
13    // MapLibre Style Specification layout properties
14  }
15});
  • filter写法栗子:如果shownames中包含了‘全部’两个字显示当前区域的所有镇,如果没有则匹配当前区域文字中出现的镇名
1{
2          id: 'town_fillLayer',
3          type: 'fill',
4          source: 'caec8e3ae4ade',
5          'source-layer': 'jjyzq_yjxzq_cq_poly',
6          filter: showNames.includes('全部')
7            ? [
8                'all',
9                ['>=', ['get', 'code'], Number(`${code}000`)],
10                ['<=', ['get', 'code'], Number(`${Number(code) + 1}000`)],
11              ]
12            : [
13                'all',
14                ['>=', ['get', 'code'], Number(`${code}000`)],
15                ['<=', ['get', 'code'], Number(`${Number(code) + 1}000`)],
16                ['in', ['get', 'name'], showNames],
17              ],
18          paint: {
19            'fill-color': color,
20          },
21          metadata: {
22            beforeId: 'admin_cn',
23          },
24        },
  • map.addSource():将源添加到地图的样式中,触发 source.add 事件。
1map.addSource('my-data', {
2  "type": "geojson",
3  "data": {
4    "type": "Feature",
5    "geometry": {
6      "type": "Point",
7      "coordinates": [-77.0323, 38.9131]
8    },
9    "properties": {
10      "title": "Mapbox DC",
11      "marker-symbol": "monument"
12    }
13  }
14});
  • map.addSprite():添加雪碧图到地图中
1map.addSprite('sprite-two', 'http://example.com/sprite-two');
  • map.flyTo():更改中心、缩放、方位角和俯仰的任意组合,使沿曲线的过渡动画化,让人联想到飞行。该动画无缝地结合了缩放和平移,以帮助用户即使在穿越很远的距离后也能保持方位。
1// fly with default options to null island
2map.flyTo({center: [0, 0], zoom: 9});
3// using flyTo options
4map.flyTo({
5  center: [0, 0],
6  zoom: 9,
7  speed: 0.2,
8  curve: 1,
9  easing(t) {
10    return t;
11  }
12});
  • popUp:乡地图添加popup
1let popup = new Popup({offset: popupOffsets, className: 'my-class'})
2  .setLngLat(e.lngLat)
3  .setHTML("<h1>Hello World!</h1>")
4  .setMaxWidth("300px")
5  .addTo(map);
  • marker:向地图中添加标记
1let marker = new Marker({
2    color: "#FFFFFF",
3    draggable: true
4  }).setLngLat([30.5, 50.5])
5  .addTo(map);
  • 在地图中绘制图案
1//使用draw.create监听绘制
2_map.on('draw.create', async (e) => {
3      if (getSelect() === 'drawGrid') {
4        drawCreateHandler(true)
5        getValueByDraw(_map)
6      }
7    })
8
9//通过changeMode实现连续绘制
10const drawCreateHandler = (isSelect: boolean) => {
11    if (isSelect) {
12      setTimeout(() => {
13        drawRef.current.changeMode(DrawModes.FREEHAND_POLYGON)
14      }, 50)
15    } else {
16      try {
17        drawRef.current.deleteAll()
18      } catch (error) {
19        console.log(error)
20      }
21    }
22  }
补充:添加source时,可通过clusterRadius来控制显示点的密度