首页 > 其他分享 >Mapbox实战项目(1)-栅格图片图层实现地图方位展示

Mapbox实战项目(1)-栅格图片图层实现地图方位展示

时间:2024-03-05 21:44:06浏览次数:26  
标签:map const center 地图 栅格 坐标 Mapbox 图层 图片

需求背景

需要实现地图上展示一个类似于罗盘的标记,随着地图的缩放、切换、旋转等,能够在地图的中央指示出地图的方位。
系统自带的方位控件太小,在特殊业务场景下不够醒目。

技术选型

Mapbox

实现分析

  1. 官网已经有地图上展示图片矢量图层的demo,“Add a raster image to a map layer”和“Add a pattern to a polygon”。注意看前者和后者的区别,前者主要用一张图片覆盖到指定的一个多边形区域;而后者则会用图片区填充一个多边形区域,如果图片太小,矩形区域太大,则会重复叠加多张图片直到矩形区域填充满。
  2. 从地图开放的接口上来看,我们需要监听的主要地图交互事件有:拖拽、缩放、旋转。可在这三个事件完成时重新调整矢量图片的中心位置,重新绘制图层;
  3. 重新绘制图片图层时,需要注意地图的旋转角度(bearing)参数,在交互事件结束时实时获取当前地图的中心点和旋转角度,计算图片重新“贴”的位置;
  4. 通过“Add a raster image to a map layer”示例了解到,往地图上“贴”一张图片需要定义四个经纬度坐标用来确定图片的“粘贴”位置,这样在进行地图旋转或者调整俯视角度的时候就可以紧贴地图跟随地图一起变化。
  5. 当用户在交互的过程中,需要使用以地图中心点(全屏下:屏幕中心点)计算图片在地图坐标系中的四个经纬度坐标。因此我们需要将图片放在屏幕中间,同时计算出图片在屏幕上的四个屏幕坐标点,通过mapbox提供的屏幕坐标点转经纬度坐标接口进行转换。
  6. 在屏幕坐标系转地图坐标系时,需要注意图片的旋转角度。mapbox的bearing是逆时针旋转,原始的屏幕坐标点在经过指定的角度旋转之后获得一个新的屏幕坐标点,再将旋转后的坐标点通过mapbox的屏幕坐标点转经纬度坐标点就可以得到一个“贴”图的目标经纬度坐标。
  7. mapbox针对图片图层的位置更新可以通过sourcesetCoordinates(newCoordinates)进行更新,设置以后调用 map.triggerRepaint()触发地图重绘,届时功成;

代码实现

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Add a raster image to a map layer</title>
    <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
    <link href="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css" rel="stylesheet">
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js"></script>
    <style>
        body {
            margin: 0;
            padding: 0;
        }

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

<body>
    <div id="map"></div>
    <script>
        mapboxgl.accessToken = '你的KEY';
        const map = new mapboxgl.Map({
            container: 'map',
            zoom: 10,
            center: [103, 30],
            // Choose from Mapbox's core styles, or make your own style with Mapbox Studio
            style: 'mapbox://styles/mapbox/light-v11'
        });

        //图层的长宽尺寸, 务必和真实图片的长宽保持一致,本教程使用的是正方形,矩形同理可实现。
        const imgWidth = 632;
        const corners = getImgcornersAtMapCenter(map, imgWidth)

        map.on('load', () => {        
            map.addSource('compass', {
                'type': 'image',
                'url': './assets/823VemjWvJ.png',
                'coordinates': corners
            });
            map.addLayer({
                "id": 'radar-layer',
                'type': 'raster',
                'source': 'compass',
                'paint': {
                    'raster-fade-duration': 0
                }
            });
        });

        //拖拽结束重新绘图
        map.on("dragend", () => {
            var source = map.getSource("compass");
            var corners = getImgcornersAtMapCenter(map, imgWidth);
            source.setCoordinates(corners);
            map.triggerRepaint();
        });

        //添加zoomend事件监听器
        map.on("zoomend", () => {
            var source = map.getSource("compass");
            var corners = getImgcornersAtMapCenter(map, imgWidth);
            source.setCoordinates(corners);
            map.triggerRepaint();
        });        

        function getImgcornersAtMapCenter(map, imgWidth) {
            //获取地图的bearing参数
            const bearing = map.getBearing();

            // 获取地图容器的宽度和高度
            const mapWidth = map.getCanvas().width;
            const mapHeight = map.getCanvas().height;

            //计算图片在地图上的显示区域的左上角和右下角的屏幕坐标
            const imageTopLeft = [(mapWidth - imgWidth) / 2, (mapHeight - imgWidth) / 2];
            const imageBottomRight = [imageTopLeft[0] + imgWidth, imageTopLeft[1] + imgWidth];

            //计算图片旋转后的左上角和右下角
            var rotatedcoordinates = rotatecoordinates(imageTopLeft, imageBottomRight, 0 - bearing)

            // 将屏幕坐标转换为经纬度坐标
            const topLeftCoordinates = map.unproject(rotatedcoordinates[0]);
            const bottomRightcoordinates = map.unproject(rotatedcoordinates[1]);

            return new Array(
                [topLeftCoordinates.lng, topLeftCoordinates.lat], // Northwest corner
                [bottomRightcoordinates.lng, topLeftCoordinates.lat], // Southwest corner
                [bottomRightcoordinates.lng, bottomRightcoordinates.lat], //// Southeast corner 
                [topLeftCoordinates.lng, bottomRightcoordinates.lat] //Northeast corner
            )
        }

        function rotatecoordinates(topLeft, bottomRight, bearing) {
            const center = [
                (topLeft[0] + bottomRight[0]) / 2,
                (topLeft[1] + bottomRight[1]) / 2
            ];
            //计算左上角相对于中心点的偏移
            const offsetX1 = topLeft[0] - center[0];
            const offsetY1 = topLeft[1] - center[1];

            //计算右下角相对于中心点的偏移
            const offsetX2 = bottomRight[0] - center[0];
            const offsetY2 = bottomRight[1] - center[1];

            const bearingRad = bearing * (Math.PI / 180);
            //计算旋转后的左上角坐标
            const rotatedX1 = offsetX1 * Math.cos(bearingRad) - offsetY1 * Math.sin(bearingRad);
            const rotatedY1 = offsetX1 * Math.sin(bearingRad) + offsetY1 * Math.cos(bearingRad);

            // 计算旋转后的右下角坐标
            const rotatedX2 = offsetX2 * Math.cos(bearingRad) - offsetY2 * Math.sin(bearingRad);
            const rotatedY2 = offsetX2 * Math.sin(bearingRad) + offsetY2 * Math.cos(bearingRad);

            //将旋转后的坐标加上中心点的偏移,得到最终坐标
            const rotatedTopLeft = [rotatedX1 + center[0], rotatedY1 + center[1]];
            const rotatedBottomRight = [rotatedX2 + center[0], rotatedY2 + center[1]];
            return new Array(rotatedTopLeft, rotatedBottomRight);
        }        
    </script>

</body>

</html>

效果截图


思考问题

【问】贴图后的图片是否“遮挡”了地图本身的事件交互?
【答】可以调整image图层在地图众图层中的位置人,让它处于最底层;

其他

离线地图服务器,有需求就提issue:mapbox-offline-server

标签:map,const,center,地图,栅格,坐标,Mapbox,图层,图片
From: https://www.cnblogs.com/liushaofeng89/p/18054954

相关文章

  • MapBox信息补填
    Mapbox目前仍然不允许国内用户注册(但可以登录使用,奇怪了),近期已注册的账号也让补充一些信息,很多人不知道怎么填写,为源GIS来帮您详细讲解说明一下。问题描述2024年Mapbox官网注册账号发生一些变化,注册时需要填写账号的类别是个人使用还是商业用途。以前注册过的账号,登录时,强制要......
  • PS 第五节 形状工具 + 图层样式
    PS第五节形状工具+图层样式......
  • Openlayer加载mapboxgl矢量图层
    注意Openlayer的版本Openlayer是支持直接加载矢量图层的,如下图层会没有样式渲染<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0&q......
  • C++ GDAL用CreateCopy()新建栅格并修改波段的个数
      本文介绍基于C++语言GDAL库,为CreateCopy()函数创建的栅格图像添加更多波段的方法。  在C++语言的GDAL库中,我们可以基于CreateCopy()函数与Create()函数创建新的栅格图像文件。其中,CreateCopy()函数需要基于一个已有的栅格图像文件作为模板,将模板文件的各项属性信息(例如空间......
  • 栅格数据
       “栅格”还起源于电视技术,一种扫描模式(如阴极射线管中的电子束),其中从上到下成行从一侧到另一侧扫描一个区域。从栅格这个词的来源,我们可以看出耕地和电视扫描,都是在进行一种网格化的过程。这种网格化的结果:产生了由像素(微小的彩色方块)网格构建的图像,这种图像就是栅格......
  • python处理栅格数据
    字节序列:ReadRaster([xoff],[yoff],[xsize],[ysize],[buf_xsize],[buf_ysize],[buf_type],[band_list],[buf_pixel_space],[buf_line_space],[buf_band_space])xoff是列读取起点,默认值为0。yoff是行读取起点,默认值为0。xsize是读取的列数,默认为全部读取。ysize是读取的......
  • python使用栅格计算器
    重采样是指根据一类象元的信息内插出另一类象元信息的过程。在遥感中,重采样是从高分辨率遥感影像中提取出低分辨率影像的过程。常用的重采样方法有最邻近内插法、双线性内插法和三次卷积法内插。  ReadAsArray函数可以重采样读取的数据,并且指定输出缓冲区大小或传递一个已有......
  • vue 高德图层---省市区行政图层显示
    官网文档:https://lbs.amap.com/api/javascript-api-v2/guide/layers/districtlayervarmap;vardistProvince;initMap(){//初始化地图AMapLoader.load({key:'申请的key',version:'2.0',//需要使用JSAPI2.0版本。若从1.x版本......
  • 创建大量栅格文件并分别写入像元数据:C++ GDAL代码实现
      本文介绍基于C++语言GDAL库,批量创建大量栅格遥感影像文件,并将数据批量写入其中的方法。  首先,我们来明确一下本文所需实现的需求。已知我们对大量遥感影像进行了批量读取与数据处理操作——具体过程可以参考文章C++GDAL提取多时相遥感影像中像素随时间变化的数值数组;而随......
  • PS 第二节 图层与蒙版
    PS基础第二节图层与蒙版......