Reputation: 5355
I would like to color certain grid tiles based on their coordinates.
I created the following grid:
<!DOCTYPE html>
<html>
<head>
<title>Color Tiles</title>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Make sure you put this AFtER leaflet.js, when using with leaflet
<script src="https://unpkg.com/[email protected]/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 © <a href="http://www.osm.org">OpenStreetMap</a>',
}).addTo(map)
tiles.addTo(map)
</script>
</body>
</html>
I would like to have the following:
I tried to style it directly via css, which seems to work. However, I would like to style it based on the provided coordinates.
Any suggestion how to do this?
Upvotes: 1
Views: 1385
Reputation: 10886
Looking at your other question about using maps for a turn-based game, there may be some ambiguity over what "coordinates" means. You may mean geographic coordinates (i.e. latitude and longitude) which represents a point on a map or globe. On the other hand, you may mean coordinates to a tile (e.g. the 4th row, 5th column, at zoom level 3 of a certain tileset) which would represent an area on a map or globe. I'll go over approaches for both cases.
Leaflet has built in ways to detect whether specific LatLng
coordinates are within bounds, by using the LatLngBounds
.contains
method.
First you can define an array of key coordinates and then create leaflet LatLng
objects from them:
var keyCoordinates = [
[ -5.9, -123.9 ],
[ -12, -28.5 ]
];
var leafletKeyCoordinates = keyCoordinates.map(function (c) {
return new L.LatLng(c[0], c[1]);
});
To determine the boundaries of a specific tile, you can calculate the southwest corner of the tile. From this part:
// 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);
Add:
// 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);
From there, you can use the bounds for each tile to determine whether it should be shaded. You can do this by either drawing on the canvas or applying a class to the tile. For an example using the canvas, at the bottom of createTile
, add:
// 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);
}
All Together:
<!DOCTYPE html>
<html>
<head>
<title>Color Tiles</title>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Make sure you put this AFtER leaflet.js, when using with leaflet
<script src="https://unpkg.com/[email protected]/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 © <a href="http://www.osm.org">OpenStreetMap</a>',
}).addTo(map)
tiles.addTo(map)
</script>
</body>
</html>
In the case of tiles, you can directly look at coords.x
and coords.y
for the column and row, and coords.z
for the zoom level. The tricky part of this is that if there are varying levels of zoom, your user may be at a different zoom than the tiles you've identified.
var tileCoordinates = [
[0, 3, 3], // x, y, and zoom of tile
[28, 6, 5]
];
To translate between zoom levels, each zoom level doubles the tile coordinates (for example, the tile (0, 2) at zoom level 4 is represented by the tiles (0, 4), (0, 5), (1, 4), (1, 5) at zoom level 5)). We can use Math.pow(2, targetZoom - coords.z)
or Math.pow(2, coords.z - targetZoom)
to determine the factor to multiply by.
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;
});
All together:
<!DOCTYPE html>
<html>
<head>
<title>Color Tiles</title>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Make sure you put this AFtER leaflet.js, when using with leaflet
<script src="https://unpkg.com/[email protected]/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 © <a href="http://www.osm.org">OpenStreetMap</a>',
}).addTo(map)
tiles.addTo(map)
</script>
</body>
</html>
Upvotes: 2
Reputation: 1353
This snippet simultaneously solves the related question. It decides which tiles to color based on an array of TileNumber
objects:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GridLayer Test</title>
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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://unpkg.com/[email protected]/dist/leaflet.js"></script>
<script>
const numTilesX = 2 ** 17
const numTilesY = 2 ** 17
class TileNumber {
constructor(x, y) {
this.x = x;
this.y = y;
}
equals(other) {
return this.x === other.x && this.y === other.y;
}
}
let coloredTiles = [
new TileNumber(70435, 45249),
new TileNumber(70434, 45248),
new TileNumber(70441, 45245)
]
function latLngToTileNumber(latLng) {
const lngDegrees = latLng.lng;
const latRadians = latLng.lat * (Math.PI/180);
return new L.Point(
numTilesX * ((lngDegrees + 180) / 360),
numTilesY * (1 - Math.log(Math.tan(latRadians) + 1 / Math.cos(latRadians)) / Math.PI) / 2
);
}
const map = new L.Map('map', {center: [48.5748229, 13.4609744], zoom: 16, maxZoom: 19});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © <a href="https://www.osm.org">OpenStreetMap</a>', maxZoom: 19
}).addTo(map)
const tiles = new L.GridLayer({minZoom: 12});
tiles.createTile = function (coords) {
const tile = L.DomUtil.create('canvas', 'leaflet-tile');
const ctx = tile.getContext('2d');
const size = this.getTileSize();
tile.width = size.x
tile.height = size.y
// calculate projection coordinates of top left tile pixel
const nwPoint = coords.scaleBy(size);
// calculate geographic coordinates of top left tile pixel
const nw = map.unproject(nwPoint, coords.z);
// calculate fraction tile number at top left point
const nwTile = latLngToTileNumber(nw, Math.floor)
// calculate projection coordinates of bottom right tile pixel
const sePoint = new L.Point(nwPoint.x + size.x - 1, nwPoint.y + size.y - 1)
// calculate geographic coordinates of bottom right tile pixel
const se = map.unproject(sePoint, coords.z);
// calculate fractional tile number at bottom right point
const seTile = latLngToTileNumber(se, Math.ceil)
const minTileX = nwTile.x
const maxTileX = seTile.x
const minTileY = nwTile.y
const maxTileY = seTile.y
for (let x = Math.ceil(minTileX) - 1; x <= Math.floor(maxTileX) + 1; x++) {
for (let y = Math.ceil(minTileY) - 1; y <= Math.floor(maxTileY) + 1; y++) {
let tile = new TileNumber(x, y)
const xMinPixel = Math.round(size.x * (x - minTileX) / (maxTileX - minTileX));
const xMaxPixel = Math.round(size.x * (x + 1 - minTileX) / (maxTileX - minTileX));
const yMinPixel = Math.round(size.y * (y - minTileY) / (maxTileY - minTileY));
const yMaxPixel = Math.round(size.y * (y + 1 - minTileY) / (maxTileY - minTileY));
// fill the rectangle with a color
ctx.fillStyle = coloredTiles.some(t => t.equals(tile))
? 'rgba(0, 0, 255, 0.3)'
: 'rgba(255, 255, 255, 0)';
ctx.fillRect(xMinPixel, yMinPixel, xMaxPixel - xMinPixel, yMaxPixel - yMinPixel);
if (coords.z >= 16) {
// draw the white rectangle and text at the top of the cell
ctx.fillStyle = 'white';
ctx.fillRect(xMinPixel, yMinPixel, xMaxPixel - xMinPixel, 28);
ctx.fillStyle = 'black';
ctx.font = "15px Arial"
ctx.fillText(tile.x + "," + tile.y, xMinPixel + 10, yMinPixel + 20, xMaxPixel - xMinPixel);
}
if (coords.z >= 13) {
// draw a border
ctx.strokeStyle = 'black';
ctx.strokeRect(xMinPixel, yMinPixel, xMaxPixel - xMinPixel, yMaxPixel - yMinPixel);
}
}
}
return tile;
}
tiles.addTo(map);
map.on('click', e => {
const fractionalTileNumber = latLngToTileNumber(e.latlng);
const tileNumber = new TileNumber(Math.floor(fractionalTileNumber.x), Math.floor(fractionalTileNumber.y));
console.log("Tile " + tileNumber.x + " " + tileNumber.y + " clicked");
if (coloredTiles.some(t => t.equals(tileNumber))) {
coloredTiles = coloredTiles.filter(t => !t.equals(tileNumber));
} else {
coloredTiles.push(tileNumber);
}
tiles.redraw();
});
</script>
</body>
</html>
Upvotes: 1
Reputation: 11338
You can use the internal _tileCoordsToBounds
function from Leaflet to get the bounds of the tile and check if the latlng is in it.
I extended L.GridLayer
because it is much cleaner. The important function is _isLatLngInCoords
:
L.ColoredTiles = L.GridLayer.extend({
colorLatLngs: [],
initialize (latlngs, options) {
L.Util.setOptions(this, options);
if(latlngs && L.Util.isArray(latlngs) && latlngs.length > 0) {
this.colorLatLngs = latlngs;
}
if(this.options.debug) {
this._showDebugLatLngs();
}
},
createTile (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();
if (this._isLatLngInCoords(coords)) {
ctx.fillStyle = 'rgba(0, 0, 240, 0.3)';
ctx.fillRect(0, 0, size.x, size.y);
}
return tile;
},
_isLatLngInCoords(coords) {
var tileBounds = this._tileCoordsToBounds(coords);
return this.colorLatLngs && this.colorLatLngs.some(function (a) {
return tileBounds.contains(a);
});
},
setColorLatLngs(latlngs){
this.colorLatLngs = latlngs;
this.redraw();
if(this.options.debug) {
this._showDebugLatLngs();
}
},
_showDebugLatLngs(){
this.fg = this.fg || L.featureGroup().addTo(map);
this.fg.clearLayers();
this.colorLatLngs && this.colorLatLngs.forEach((latlng)=>{
L.marker(latlng).addTo(this.fg);
})
}
});
And then add it to the map:
var colorLatLngs = [
L.latLng(0,0),
L.latLng(2,2),
];
var tiles = new L.ColoredTiles(colorLatLngs).addTo(map)
I also added the function setColorLatLngs(array)
to change the latlngs and update the colored tiles.
tiles.setColorLatLngs([L.latLng(3,3)]);
And for the debug purpose I added the option debug: true
to set markers on each latlng. So it is clearly visible which tiles should be colored.
var tiles = new L.ColoredTiles(colorLatLngs, {debug: true}).addTo(map)
<!DOCTYPE html>
<html>
<head>
<title>Color Tiles</title>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Make sure you put this AFtER leaflet.js, when using with leaflet
<script src="https://unpkg.com/[email protected]/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)
L.ColoredTiles = L.GridLayer.extend({
colorLatLngs: [],
initialize (latlngs, options) {
L.Util.setOptions(this, options);
if(latlngs && L.Util.isArray(latlngs) && latlngs.length > 0) {
this.colorLatLngs = latlngs;
}
if(this.options.debug) {
this._showDebugLatLngs();
}
},
createTile (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();
if (this._isLatLngInCoords(coords)) {
ctx.fillStyle = 'rgba(0, 0, 240, 0.3)';
ctx.fillRect(0, 0, size.x, size.y);
}
return tile;
},
_isLatLngInCoords(coords) {
var tileBounds = this._tileCoordsToBounds(coords);
return this.colorLatLngs && this.colorLatLngs.some(function (a) {
return tileBounds.contains(a);
});
},
setColorLatLngs(latlngs){
this.colorLatLngs = latlngs;
this.redraw();
if(this.options.debug) {
this._showDebugLatLngs();
}
},
_showDebugLatLngs(){
this.fg = this.fg || L.featureGroup().addTo(map);
this.fg.clearLayers();
this.colorLatLngs && this.colorLatLngs.forEach((latlng)=>{
L.marker(latlng).addTo(this.fg);
})
}
});
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data © <a href="http://www.osm.org">OpenStreetMap</a>',
}).addTo(map)
var colorLatLngs = [
L.latLng(0,0),
L.latLng(2,2),
];
var tiles = new L.ColoredTiles(colorLatLngs, {debug: true}).addTo(map)
</script>
</body>
</html>
Upvotes: 2
Reputation: 520
I'm thinking about something this way :
Added :
if (nw.lat > 10) {
ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
ctx.fillRect(0, 50, size.x, size.y - 50);
}
Up to you to use any condition that allow you to localize the tiles.
<!DOCTYPE html>
<html>
<head>
<title>Color Tiles</title>
<meta charset="utf-8" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/[email protected]/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/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://unpkg.com/[email protected]/dist/leaflet.js"></script>
<!-- Make sure you put this AFtER leaflet.js, when using with leaflet
<script src="https://unpkg.com/[email protected]/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);
if (nw.lat > 10) {
ctx.fillStyle = "rgba(0, 0, 0, 0.4)";
ctx.fillRect(0, 50, size.x, size.y - 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 © <a href="http://www.osm.org">OpenStreetMap</a>',
}).addTo(map)
tiles.addTo(map)
</script>
</body>
</html>
Upvotes: 2