根据坐标为某些网格切片上色

2022-07-15 00:00:00 openstreetmap leaflet javascript

我想根据某些网格磁贴的坐标为其上色。

我创建了以下网格:

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
<!DOCTYPE html>
<html>

<head>
    <title>Color Tiles</title>
    <meta charset="utf-8" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />

    <style>
        body {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        #map {
            height: 100%;
            width: 100%;
        }
    </style>
</head>

<body>

  <div id="map"></div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>

    <!-- Make sure you put this AFtER leaflet.js, when using with leaflet 
    <script src="https://unpkg.com/leaflet-geosearch@3.0.0/dist/geosearch.umd.js"></script>
    -->

    <script>
        var map = new L.Map('map', { center: [10, 0], zoom: 2 });

        let zoomLevel = map.getZoom()
        console.log("zoomLevel " + zoomLevel)

        // if(zoomLevel === 1) {
            var tiles = new L.GridLayer();
            tiles.createTile = function (coords) {
                var tile = L.DomUtil.create('canvas', 'leaflet-tile');
                var ctx = tile.getContext('2d');
                var size = this.getTileSize()
                // console.log("size: " + size.toString())
                tile.width = size.x
                tile.height = size.y

                // calculate projection coordinates of top left tile pixel
                var nwPoint = coords.scaleBy(size)

                // calculate geographic coordinates of top left tile pixel
                var nw = map.unproject(nwPoint, coords.z)

                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, size.x, 50);
                ctx.fillStyle = 'black';
                ctx.fillText('x: ' + coords.x + ', y: ' + coords.y + ', zoom: ' + coords.z, 20, 20);
                ctx.fillText('lat: ' + nw.lat + ', lon: ' + nw.lng, 20, 40);
                ctx.strokeStyle = 'black';
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(size.x - 1, 0);
                ctx.lineTo(size.x - 1, size.y - 1);
                ctx.lineTo(0, size.y - 1);
                ctx.closePath();
                ctx.stroke();
                return tile;
            }

            L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>',
            }).addTo(map)

            tiles.addTo(map)
    
    </script>
</body>

</html>

我想要以下物品:

我尝试通过css直接设置样式,这似乎很管用。但是,我想根据提供的坐标设置样式。

有什么建议如何做到这一点吗?


解决方案

什么类型的坐标?

查看您在回合游戏中使用地图的另一个问题,对于坐标的含义可能有些模棱两可。您可能指的是地理坐标(即纬度和经度),表示地图或地球仪上的点。另一方面,您可能表示表示地图或地球上某个区域的磁贴(例如,第4行、第5列,位于特定磁贴集的缩放级别3)的坐标。我会仔细检查两种情况下的处理方法。

地理坐标

let内置了通过使用LatLngBounds.contains method检测特定LatLng coordinates是否在范围内的方法。

首先您可以定义一个按键坐标数组,然后根据它们创建传单LatLng objects:

var keyCoordinates = [
  [ -5.9, -123.9 ],
  [ -12, -28.5 ]
];
var leafletKeyCoordinates = keyCoordinates.map(function (c) {
  return new L.LatLng(c[0], c[1]);
});

要确定特定瓷砖的边界,可以计算瓷砖的西南角。此部分:

// calculate projection coordinates of top left tile pixel
var nwPoint = coords.scaleBy(size)
// calculate geographic coordinates of top left tile pixel
var nw = map.unproject(nwPoint, coords.z);

添加:

// calculate projection coordinates of bottom right tile pixel
var sePoint = nwPoint.add(size);
// calculate geographic coordinates of bottom right tile pixel
var se = map.unproject(sePoint, coords.z);
var bounds = new L.LatLngBounds(nw, se);

从那里,您可以使用每个平铺的边界来确定是否应该对其进行着色。您可以通过在画布上绘制或将类应用于平铺来完成此操作。对于使用画布的示例,在createTile的底部添加:

// if it contains any coordinates, it should be filled
var shouldShade = leafletKeyCoordinates.some(function (a) {
  return bounds.contains(a);
});
if (shouldShade) {
  ctx.fillStyle = 'rgba(0, 0, 240, 0.3)';
  ctx.fillRect(0, 0, size.x, size.y);
}

全部:

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
<!DOCTYPE html>
<html>

<head>
    <title>Color Tiles</title>
    <meta charset="utf-8" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />

    <style>
        body {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        #map {
            height: 100%;
            width: 100%;
        }
    </style>
</head>

<body>

  <div id="map"></div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>

    <!-- Make sure you put this AFtER leaflet.js, when using with leaflet 
    <script src="https://unpkg.com/leaflet-geosearch@3.0.0/dist/geosearch.umd.js"></script>
    -->

    <script>
        var map = new L.Map('map', { center: [10, 0], zoom: 2 });

        let zoomLevel = map.getZoom()
        console.log("zoomLevel " + zoomLevel)

        var keyCoordinates = [
          [ -5.9, -123.9 ],
          [ -12, -28.5 ]
        ];
        var leafletKeyCoordinates = keyCoordinates.map(function (c) {
          return new L.LatLng(c[0], c[1]);
        });

        // if(zoomLevel === 1) {
            var tiles = new L.GridLayer();
            tiles.createTile = function (coords) {
                var tile = L.DomUtil.create('canvas', 'leaflet-tile');
                var ctx = tile.getContext('2d');
                var size = this.getTileSize()
                // console.log("size: " + size.toString())
                tile.width = size.x
                tile.height = size.y

                // calculate projection coordinates of top left tile pixel
                var nwPoint = coords.scaleBy(size)

                // calculate geographic coordinates of top left tile pixel
                var nw = map.unproject(nwPoint, coords.z)
                // calculate projection coordinates of bottom right tile pixel
                var sePoint = nwPoint.add(size);
                // calculate geographic coordinates of bottom right tile pixel
                var se = map.unproject(sePoint, coords.z);
                var bounds = new L.LatLngBounds(nw, se);

                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, size.x, 50);
                ctx.fillStyle = 'black';
                ctx.fillText('x: ' + coords.x + ', y: ' + coords.y + ', zoom: ' + coords.z, 20, 20);
                ctx.fillText('lat: ' + nw.lat + ', lon: ' + nw.lng, 20, 40);
                ctx.strokeStyle = 'black';
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(size.x - 1, 0);
                ctx.lineTo(size.x - 1, size.y - 1);
                ctx.lineTo(0, size.y - 1);
                ctx.closePath();
                ctx.stroke();

                // if it contains any coordinates, it should be filled
                var shouldShade = leafletKeyCoordinates.some(function (a) {
                  return bounds.contains(a);
                });
                if (shouldShade) {
                  ctx.fillStyle = 'rgba(0, 0, 240, 0.3)';
                  ctx.fillRect(0, 0, size.x, size.y);
                }
return tile;
            }

            L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>',
            }).addTo(map)

            tiles.addTo(map)
    
    </script>
</body>

</html>

平铺坐标

对于平铺,您可以直接查看列和行的coords.xcoords.y,以及缩放级别的coords.z。这种情况的棘手之处在于,如果存在不同的缩放级别,您的用户的缩放比例可能与您标识的磁贴的缩放比例不同。

var tileCoordinates = [
  [0, 3, 3], // x, y, and zoom of tile
  [28, 6, 5]
];
要在缩放级别之间进行转换,每个缩放级别会使平铺坐标加倍(例如,缩放级别4的平铺(0,2)由缩放级别5的平铺(0,4)、(0,5)、(1,4)、(1,5)表示))。我们可以使用Math.pow(2, targetZoom - coords.z)Math.pow(2, coords.z - targetZoom)来确定要乘以的因子。

var { x, y, z } = coords;
var shouldShade = tileCoordinates.some(function (c) {
  let [ tx, ty, tz] = c, multiple, sx, sy;
  if (z < tz) {
     // map is zoomed out from the target
     // you may just want to `return false;` here
     multiple = Math.pow(2, tz - z);
     sx = Math.floor(tx / multiple);
     sy = Math.floor(ty / multiple);
     return sx === x && sy === y; 
  } else if (z > tz) {
     // map is zoomed in from the target
     multiple = Math.pow(2, z - tz);
     sx = Math.floor(x / multiple);
     sy = Math.floor(y / multiple);
     return sx === tx && sy === ty; 
  }
  return tx === x && ty === y;
});

加在一起:

<!DOCTYPE html>
<html>

<head>
    <title>Color Tiles</title>
    <meta charset="utf-8" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" />

    <style>
        body {
            padding: 0;
            margin: 0;
        }

        html,
        body,
        #map {
            height: 100%;
            width: 100%;
        }
    </style>
</head>

<body>

  <div id="map"></div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://unpkg.com/leaflet@1.0.1/dist/leaflet.js"></script>

    <!-- Make sure you put this AFtER leaflet.js, when using with leaflet 
    <script src="https://unpkg.com/leaflet-geosearch@3.0.0/dist/geosearch.umd.js"></script>
    -->

    <script>
        var map = new L.Map('map', { center: [10, 0], zoom: 2 });

        let zoomLevel = map.getZoom()
        console.log("zoomLevel " + zoomLevel)

        var tileCoordinates = [
          [0, 3, 3],
          [28, 6, 5]
        ];

        // if(zoomLevel === 1) {
            var tiles = new L.GridLayer();
            tiles.createTile = function (coords) {
                var tile = L.DomUtil.create('canvas', 'leaflet-tile');
                var ctx = tile.getContext('2d');
                var size = this.getTileSize()
                // console.log("size: " + size.toString())
                tile.width = size.x
                tile.height = size.y

                // calculate projection coordinates of top left tile pixel
                var nwPoint = coords.scaleBy(size)

                // calculate geographic coordinates of top left tile pixel
                var nw = map.unproject(nwPoint, coords.z)
                // calculate projection coordinates of bottom right tile pixel
                var sePoint = nwPoint.add(size);
                // calculate geographic coordinates of bottom right tile pixel
                var se = map.unproject(sePoint, coords.z);
                var bounds = new L.LatLngBounds(nw, se);

                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, size.x, 50);
                ctx.fillStyle = 'black';
                ctx.fillText('x: ' + coords.x + ', y: ' + coords.y + ', zoom: ' + coords.z, 20, 20);
                ctx.fillText('lat: ' + nw.lat + ', lon: ' + nw.lng, 20, 40);
                ctx.strokeStyle = 'black';
                ctx.beginPath();
                ctx.moveTo(0, 0);
                ctx.lineTo(size.x - 1, 0);
                ctx.lineTo(size.x - 1, size.y - 1);
                ctx.lineTo(0, size.y - 1);
                ctx.closePath();
                ctx.stroke();

                var { x, y, z } = coords;
                var shouldShade = tileCoordinates.some(function (c) {
                  let [ tx, ty, tz] = c, multiple, sx, sy;
                  if (z < tz) {
                    // map is zoomed out from the target
                    // you may just want to `return false;` here
                    multiple = Math.pow(2, tz - z);
                    sx = Math.floor(tx / multiple);
                    sy = Math.floor(ty / multiple);
                    return sx === x && sy === y; 
                  } else if (z > tz) {
                    // map is zoomed in from the target
                    multiple = Math.pow(2, z - tz);
                    sx = Math.floor(x / multiple);
                    sy = Math.floor(y / multiple);
                    return sx === tx && sy === ty; 
                  }
                  return tx === x && ty === y;
                });

                if (shouldShade) {
                  ctx.fillStyle = 'rgba(0, 0, 240, 0.3)';
                  ctx.fillRect(0, 0, size.x, size.y);
                }
return tile;
            }

            L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
                attribution: 'Map data &copy; <a href="http://www.osm.org">OpenStreetMap</a>',
            }).addTo(map)

            tiles.addTo(map)
    
    </script>
</body>

</html>

相关文章