【GeoJSON点、线、面在SF地图中的应用教程】

GeoJSON点、线、面在地图中的应用教程

SFMap

一、引言

GeoJSON是一种对各种地理数据结构进行编码的格式,常用于在地图上展示不同的地理要素,如点、线、面。本教程将详细介绍如何使用GeoJSON来表示点、线、面的单个与多个数组形式,并结合代码示例展示它们在地图上的呈现效果。我们将以顺丰地图API为例进行讲解,确保你能快速上手并应用到实际项目中。

二、准备工作

  1. 首先,你需要在顺丰地图平台申请一个开发者账号,获取对应的ak值,用于在代码中加载地图。
  2. 了解基本的HTML、JavaScript和CSS知识,因为我们的示例代码基于这些技术构建。

三、点的应用

(一)单个点

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>GeoJSON-单个点</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body { margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 9
        });

        map.on('load', function() {
            map.addSource('point', {
                'type': 'geojson',
                'data': {
                    'type': 'Feature',
                    'geometry': {
                        'type': 'Point',
                        'coordinates': [113.907826,22.643389]
                    },
                    'properties': {
                        'title': 'Marker-1',
                        'icon': '2'
                    }
                }
            });
            map.addLayer({
                'id': 'point',
                'type': 'symbol',
                'source': 'point',
                'layout': {
                    'icon-image': ['concat', 'icon_', ['get', 'icon']],
                    'text-field': ['get', 'title'],
                    'text-offset': [0, 0.6],
                    'text-anchor': 'top'
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 引入地图API并初始化地图容器、设置地图的初始中心坐标和缩放级别。
    • 使用map.addSource添加一个GeoJSON数据源,类型为Feature,几何类型是Point,指定了一个点的坐标[113.907826,22.643389],同时设置了一些属性如titleicon,用于标识和美化该点标记。
    • 通过map.addLayer添加一个图层,设置图层的idtype(这里是symbol,用于显示符号化的点)、source(关联之前定义的数据源),并在layout中配置图标和文本显示方式,比如根据icon属性获取图标,根据title属性显示文本。

(二)点的数组(多个点)

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>GeoJSON-点的数组</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body { margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 9
        });

        map.on('load', function() {
            map.addSource('points', {
                'type': 'geojson',
                'data': {
                    'type': 'FeatureCollection',
                    'features': [
                        {
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Point',
                                'coordinates': [113.907826,22.643389]
                            },
                            'properties': {
                                'title': 'Marker-1',
                                'icon': '2'
                            }
                        },
                        {
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Point',
                                'coordinates': [114.196217,22.650993]
                            },
                            'properties': {
                                'title': 'Marker-2',
                                'icon': '3'
                            }
                        }
                    ]
                }
            });
            map.addLayer({
                'id': 'points',
                'type': 'symbol',
                'source': 'points',
                'layout': {
                    'icon-image': ['concat', 'icon_', ['get', 'icon']],
                    'text-field': ['get', 'title'],
                    'text-offset': [0, 0.6],
                    'text-anchor': 'top'
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 整体结构与单个点类似,但数据源部分有所不同。这里使用FeatureCollection作为data的类型,表示一个要素集合。
    • features数组中包含多个Feature对象,每个对象都代表一个点,有各自的坐标、titleicon属性。这样就可以在地图上一次性添加多个点标记,并且每个点可以有不同的样式。

四、线的应用

(一)单条线

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>GeoJSON-单条线</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body { margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 12
        });

        map.on('load', function() {
            map.addSource('route', {
                'type': 'geojson',
                'data': {
                    'type': 'Feature',
                    'properties': {},
                    'geometry': {
                        'type': 'LineString',
                        'coordinates': [
                            [113.993571,22.590078],
                            [113.963702,22.581271],
                            [113.967478,22.550201],
                            [114.005072,22.541957],
                            [114.01829,22.5573305],
                            [114.027045,22.582856]
                        ]
                    }
                }
            });
            map.addLayer({
                'id': 'route',
                'type': 'line',
                'source': 'route',
                'layout': {
                    'line-join': 'round',
                    'line-cap': 'round'
                },
                'paint': {
                    'line-color': '#0000ff',
                    'line-width': 8
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 同样先初始化地图。
    • 数据源data中,typeFeaturegeometry.typeLineString,表示这是一条线。coordinates数组里的一系列经纬度坐标点依次连接起来形成一条连续的线。
    • 添加的图层typeline,并在layout中设置线的连接方式(line-join)和端点样式(line-cap)为圆形,在paint中设置线的颜色为蓝色(#0000ff),宽度为8px

(二)线段的数组(多条线)

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>GeoJSON-线段的数组</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body { margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 12
        });

        map.on('load', function() {
            map.addSource('routes', {
                'type': 'geojson',
                'data': {
                    'type': 'Feature',
                    'properties': {},
                    'geometry': {
                        'type': 'MultiLineString',
                        'coordinates': [
                            [
                                [113.993571, 22.590078],
                                [113.963702, 22.581271]
                            ],
                            [
                                [113.967478, 22.550201],
                                [114.005072, 22.541957]
                            ],
                            [
                                [114.01829, 22.5573305],
                                [114.027045, 22.582856]
                            ]
                        ]
                    }
                }
            });
            map.addLayer({
                'id': 'routes',
                'type': 'line',
                'source': 'routes',
                'layout': {
                    'line-join': 'round',
                    'line-cap': 'round'
                },
                'paint': {
                    'line-color': '#0000ff',
                    'line-width': 8
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 初始化地图,中心坐标和缩放级别按需设置。
    • 数据源部分,geometry.typeMultiLineString,这表示一个多线段的集合。coordinates是一个二维数组的数组,每个子数组代表一条独立的线段,其内部的坐标点连接成一条线段。
    • 图层设置与单条线类似,设置线的样式,使得多条线段都以蓝色、宽度为8px,连接和端点为圆形的样式展示。

(二)线段的数组(多条线2)

  1. 代码示例
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>GeoJSON-线段的数组</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body {
            margin: 0;
            padding: 0;
        }

        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
    </style>
</head>

<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 9
        });

        const data = {
            'type': 'geojson',
            'data': {
                'type': 'FeatureCollection',
                'features': [
                    {
                        'type': 'Feature',
                        'geometry': {
                            'type': 'LineString',
                            'coordinates': [
                                [113.907826, 22.643389],
                                [114.196217, 22.650993]
                            ]
                        },
                        'properties': {
                            id: 'Line-1',
                            'name': 'Line-1',
                            clicked: false,
                            'lineColor': '#FF0000'
                        }
                    },
                    {
                        'type': 'Feature',
                        'geometry': {
                            'type': 'LineString',
                            'coordinates': [
                                [113.95, 22.6],
                                [114.05, 22.62]
                            ]
                        },
                        'properties': {
                            id: 'Line-2',
                            'name': 'Line-2',
                            'lineColor': '#00FF00',
                            clicked: false,
                        }
                    }
                ]
            }
        }
        map.on('load', function () {
            map.addSource('lines', data);
            map.addLayer({
                'id': 'lines',
                'type': 'line',
                'source': 'lines',
                'layout': {
                    'line-join': 'round',
                    'line-cap': 'round'
                },
                'paint': {
                    'line-color': [
                        'case',
                        ['boolean', ['get', 'clicked'], false],
                        '#e55e5e',
                        '#3bb2d0'
                    ],
                    'line-width': 30
                }
            });

            // 监听点击事件--- 切换线颜色
            map.on('click', 'lines', function (e) {
                const feature = e.features[0];
                console.log(feature, map.getSource('lines'));
                const featureId = feature.properties.id;
                const features = data.data.features;

                // 先将所有点的 clicked 属性设为 false
                features.forEach((feature) => {
                    feature.properties.clicked = false;
                });

                // 再将被点击点的 clicked 属性设为 true
                for (let i = 0; i < features.length; i++) {
                    if (features[i].properties.id === featureId) {
                        features[i].properties.clicked = true;
                        break;
                    }
                }
                // 创建一个新的 GeoJSON 数据对象,避免可能的引用问题
                const newData = {
                    type: 'FeatureCollection',
                    features: features.map(feature => ({
                        type: feature.type,
                        geometry: feature.geometry,
                        properties: { ...feature.properties }
                    }))
                };
                map.getSource('lines').setData(newData);
            });
        });
    </script>
</body>

</html>   
  1. 代码解释
    下面是将上述点的数组代码改写成线段的数组,并且使用 FeatureCollection 的代码示例:

  2. 数据源:在 map.addSource 中,data 的类型为 FeatureCollection,其 features 数组包含了多个 Feature 对象,每个 Feature 对象代表一条线段。

  3. 线段几何:每个 Feature 对象中的 geometry 类型为 LineStringcoordinates 数组定义了线段的端点坐标。

  4. 线段属性:每个 Feature 对象的 properties 中包含了线段的名称(name)和颜色(lineColor)。

  5. 图层样式:在 map.addLayer 中,paint 属性中的 line-color 使用 ['get', 'lineColor'] 从每个线段的 properties 中获取颜色,line-width 设置线段的宽度为 3。

请将 你的ak值 替换为你实际申请到的 AK 值。

五、面的应用

(一)单个面

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>GeoJSON-单个面</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你的ak值"></script>
    <style>
        body { margin: 0; padding: 0; }
        #map { position: absolute; top: 0; bottom: 0; width: 100%; }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container: 'map',
            center: [113.99709, 22.56859],
            zoom: 12
        });

        map.on('load', function() {
            map.addSource('area', {
                'type': 'geojson',
                'data': {
                    'type': 'Feature',
                    'geometry': {
                        'type': 'Polygon',
                        'coordinates': [
                            [
                                [113.993571, 22.590078],
                                [113.963702, 22.581271],
                                [113.967478, 22.550201],
                                [114.005072, 22.541957],
                                [114.01829, 22.5573305],
                                [114.027045, 22.582856],
                                [113.993571, 22.590078]
                            ]
                        ]
                    },
                    'properties': {
                        'name': '区域1',
                        'fillColor': '#FF0000'
                    }
                }
            });
            map.addLayer({
                'id': 'area',
                'type': 'fill',
                'source': 'area',
                'layout': {},
                'paint': {
                    'fill-color': ['get', 'fillColor'],
                    'fill-opacity': 0.5
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 初始化地图,设置容器、中心和缩放级别。
    • 数据源data中,typeFeaturegeometry.typePolygon,表示一个多边形面。coordinates数组里的经纬度坐标点按顺序连接形成封闭的多边形,注意最后一个坐标点与第一个坐标点相同,确保多边形封闭。
    • 添加的图层typefill,用于填充多边形面。在paint中,根据fillColor属性设置填充颜色,同时设置填充透明度为0.5,使得面呈现半透明效果。

(二)面的数组(多个面)

  1. 代码示例
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>GeoJSON - 面的数组</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你申请的ak值"></script>
    <style>
        body {
            margin: 0;
            padding: 0;
        }
        #map {
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
        }
    </style>
</head>
<body>
    <div id="map"></div>
    <script>
        var map = new SFMap.Map({
            container:'map',
            center: [113.99709, 22.56859],
            zoom: 12
        });
        map.on('load', function () {
            map.addSource('areas', {
                'type': 'geojson',
                'data': {
                    'type': 'FeatureCollection',
                    'features': [
                        {
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Polygon',
                                'coordinates': [
                                    [
                                        [113.993571, 22.590078],
                                        [113.963702, 22.581271],
                                        [113.967478, 22.550201],
                                        [114.005072, 22.541957],
                                        [114.01829, 22.5573305],
                                        [114.027045, 22.582856],
                                        [113.993571, 22.590078]
                                    ]
                                ]
                            },
                            'properties': {
                                'name': '区域1',
                                'fillColor': '#FF0000'
                            }
                        },
                        {
                            'type': 'Feature',
                            'geometry': {
                                'type': 'Polygon',
                                'coordinates': [
                                    [
                                        [114.05, 22.6],
                                        [114.07, 22.6],
                                        [114.07, 22.58],
                                        [114.05, 22.58],
                                        [114.05, 22.6]
                                    ]
                                ]
                            },
                            'properties': {
                                'name': '区域2',
                                'fillColor': '#00FF00'
                            }
                        }
                    ]
                }
            });
            map.addLayer({
                'id': 'areas',
                'type': 'fill',
                'source': 'areas',
                'layout': {},
                'paint': {
                    'fill-color': ['get', 'fillColor'],
                    'fill-opacity': 0.5
                }
            });
        });
    </script>
</body>
</html>
  1. 代码解释
    • 数据结构升级:数据源data的类型为FeatureCollection,这是用于容纳多个地理要素的集合类型。features数组中包含多个Feature对象,每个对象代表一个面。每个面都有独立的geometryPolygon类型)和properties(包含名称和填充颜色等属性)。例如,第一个面描述了一个区域,坐标构成了一个多边形形状,设置填充颜色为红色(#FF0000);第二个面定义了另一个区域,坐标构成不同的多边形,填充颜色为绿色(#00FF00)。
    • 图层统一展示:添加的fill类型图层,通过['get', 'fillColor']从每个面的properties中获取填充颜色,统一设置填充透明度为0.5。这样,多个面都能以各自的颜色和半透明效果展示在地图上。

(二)面的数组(多个面2)

  1. 代码示例
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>GeoJSON-面</title>
    <meta
      name="viewport"
      content="initial-scale=1,maximum-scale=1,user-scalable=no"
    />
    <script src="https://webmap.sf-express.com/api/map?v=3.1&ak=你申请的ak值"></script>
    <style>
      body {
        margin: 0;
        padding: 0;
      }
      #map {
        position: absolute;
        top: 0;
        bottom: 0;
        width: 100%;
      }
    </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      var styleTemplate = `https://webmap-vs5.sf-express.com/MapVTService/vmapx/mapstyle/{theme}`;

      var map = new SFMap.Map({
        container: "map",
        style: styleTemplate.replace("{theme}", "allvector_enchanting-blue"),
        center: [116.400692761014, 39.850699628034],
        zoom: 18,
      });

      map.on("load", function () {
        const data1 = {
          type: "geojson",
          data: {
            type: "FeatureCollection",
            features: [
              {
                type: "Feature",
                id: 0,
                geometry: {
                  type: "MultiPolygon",
                  coordinates: [
                    [
                      [
                        [116.400683482718, 39.850699628034],
                        [116.400682519384, 39.8506886992082],
                        [116.400576207334, 39.8506988324359],
                        [116.400564865252, 39.8506999061965],
                        [116.400562496831, 39.8507001289091],
                        [116.400569347375, 39.8507570969861],
                        [116.400687861122, 39.8507455223314],
                        [116.400683482718, 39.850699628034],
                      ],
                    ],
                    [
                      [
                        [116.400755046613, 39.8506737754861],
                        [116.400721471261, 39.850671031674],
                        [116.400716721685, 39.8507409037637],
                        [116.400748935819, 39.8507434975927],
                        [116.400755046613, 39.8506737754861],
                      ],
                    ],
                    [
                      [
                        [116.400692761014, 39.8506649365395],
                        [116.400685375175, 39.8505802335779],
                        [116.400631043975, 39.850584741423],
                        [116.400638706392, 39.8506697605966],
                        [116.400692761014, 39.8506649365395],
                      ],
                    ],
                  ],
                },
                properties: {
                  x: "116.400645943918",
                  y: "39.850680291962",
                  level: 4,
                  type: 4,
                  value: 0,
                  label: "后村149号",
                  isArea: true,
                  selected: true, // 符合条件
                },
              },
            ],
          },
        };

        map.addSource("maine", data1);

        const highlightFillLayer = {
          id: "fill_highlight_ea70e077-c2df-4db0-ab27-b56bcef23e4e",
          type: "fill",
          source: "maine",
          filter: ["all", ["has", "selected"], ["==", "selected", true]], //全部满足条件才行 
          paint: {
            "fill-color": "red",
            "fill-opacity": 0.38,
          },
        };
        map.addLayer(highlightFillLayer);
      });
    </script>
  </body>
</html>

你提供的这两段代码都实现了在地图上展示多个面的功能,但它们在 GeoJSON 数据结构的表示上存在一些区别,具体如下:

(二)面的数组(对比)

  1. GeoJSON 要素类型和结构
    • 第一段代码(多个面的示例):使用的是 FeatureCollection 类型来包含多个 Feature 对象,每个 Feature 对象的 geometry 类型为 Polygon,表示单个的多边形面。也就是说,它是将每个面作为独立的 Feature 放在 features 数组中,如下所示:
{
    'type': 'FeatureCollection',
    'features': [
        {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates': [
                    // 面1的坐标数组
                ]
            },
            'properties': {
                'name': '区域1',
                'fillColor': '#FF0000'
            }
        },
        {
            'type': 'Feature',
            'geometry': {
                'type': 'Polygon',
                'coordinates': [
                    // 面2的坐标数组
                ]
            },
            'properties': {
                'name': '区域2',
                'fillColor': '#00FF00'
            }
        }
    ]
}
- **第二段代码**:使用的是单个 `Feature` 对象,其 `geometry` 类型为 `MultiPolygon`,`MultiPolygon` 的 `coordinates` 是一个二维数组,每个子数组又包含一个多边形的坐标数组。这种方式是将多个多边形组合在一个 `MultiPolygon` 几何对象中,而不是像第一段代码那样每个多边形对应一个独立的 `Feature`,如下所示:
{
    'type': 'Feature',
    'id': 0,
    'geometry': {
        'type': 'MultiPolygon',
        'coordinates': [
            [
                [
                    // 多边形1的坐标数组
                ]
            ],
            [
                [
                    // 多边形2的坐标数组
                ]
            ]
        ]
    },
    'properties': {
        'name': '区域2',
        'fillColor': '#00FF00'
    }
}
  1. 属性关联和管理

    • 第一段代码:每个面(Feature)都可以有自己独立的属性集。例如,面1有 name区域1fillColor#FF0000,面2有 name区域2fillColor#00FF00。这样在处理和管理每个面的属性时更加灵活,可以根据不同面的特点设置不同的属性。
    • 第二段代码:由于多个多边形都包含在一个 Feature 中,它们共享一套属性。在当前代码中,所有多边形都关联了 name区域2fillColor#00FF00 的属性。如果想要为不同的多边形设置不同的属性,这种结构就不太方便,需要额外的处理逻辑。
  2. 应用场景

    • 第一段代码:适用于多个面之间相对独立,每个面可能具有不同的地理意义、属性或需要单独进行操作和管理的情况。比如展示不同的行政区域、不同类型的地理区域等。
    • 第二段代码:适用于多个多边形在逻辑上属于同一个整体,具有相同的属性或需要作为一个整体进行处理的情况。例如,一个由多个子区域组成的复杂区域,这些子区域共同构成一个特定的地理对象。

综上所述,两段代码虽然都能展示多个面,但在数据结构和适用场景上存在明显的区别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值