iwmlib/lib/pixi/maps/mapprojection.html

203 lines
6.7 KiB
HTML

<!doctype html>
<html lang='en'>
<head>
<meta charset='UTF-8'>
<title>MapProjection</title>
<link rel='stylesheet' href='../../3rdparty/highlight/styles/default.css'>
<link rel='stylesheet' href='../../../css/doctest.css'>
<script src="../../../dist/iwmlib.3rdparty.js"></script>
<script src="../../../dist/iwmlib.js"></script>
<script src="../../../dist/iwmlib.pixi.js"></script>
<style>
.inline-showcase {
display: flex
}
.map-example {
display: inline-block;
width: 256px;
margin: 5px;
}
.map-container {
position: relative;
display: inline-flex;
}
.map-marker {
position: absolute;
transform: translate(-50%, -75%) scale(0.5);
}
</style>
</head>
<body onload='Doctest.run()'>
<h1>MapProjection</h1>
<p>The map projection calculates is responsible for transforming map coordinates to pixel coordinates and backwards.</p>
<h2>Static Squared World Map</h2>
<p>The most simple example is a squared world map, thats projected with mercator transformation. Ranging from
Longitude
-180 to 180 and Latitude from -90 to 90 (Exclusive, because mercator gets infinite at +/-90). </p>
<p>Coordinates:
<strong id="map_coords_0"></strong>
</p>
<div id="mapContainerGeneral" class="map-container">
<img src="../assets/maps/osm/0/0/0.png" id="map_image_0" alt="Image is missing." width="512">
</div>
<script>
let capitals = {
abidjan: { x: 5.349470, y: -4.006472 },
berlin: { x: 52.525430, y: 13.385291 },
canberra: { x: -35.282025, y: 149.128648 },
capetown: { x: -33.925448, y: 18.416962 },
moscow: { x: 55.750892, y: 37.622799 },
washington: { x: 38.895650, y: -77.031407 },
rio: { x: -22.871400, y: -43.280490 },
tokio: { x: 35.696278, y: 139.731366 }
}
const europeanCapitalCities = {
berlin: { x: 52.505949, y: 13.379400 },
london: { x: 51.5, y: -0.083333 },
rome: { x: 41.9, y: 12.483333 },
madrid: { x: 40.4, y: -3.683333 },
paris: { x: 48.833986, y: 2.346989 }
}
//Helper function to print the coordinates to a dom element.
function printCoordinates(element, mapProjection, out_dom) {
element.addEventListener("mousemove", (event) => {
let coords = mapProjection.toCoordinates({ x: event.offsetX / event.target.width, y: event.offsetY / event.target.height })
out_dom.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4)
})
}
function placeMarker(parent, position) {
const markerIconPath = "../../../assets/icons/room.png"
let marker = document.createElement("img")
marker.src = markerIconPath
marker.className = "map-marker"
Object.assign(marker.style, {
left: (position.x * 100) + "%",
top: (position.y * 100) + "%"
})
parent.appendChild(marker)
console.log(marker)
}
</script>
<script class="doctest">
// Instantiate our map projection.
let squared_world = new MapProjection(new Projection.Mercator());
// Define a position, we are interested in in {x: latitude, y: longitude}
let iceland = { x: 64.514979, y: -19.020796 }
// Gets the normalized positition of the coordinates
let pos_0 = squared_world.toPixel(iceland)
// Helper function to set the dom marker.
placeMarker(mapContainerGeneral, pos_0)
</script>
<script>
printCoordinates(map_image_0, squared_world, map_coords_0)
</script>
<h2 id="germany">Clipped Map</h2>
<p>Often we don't use the whole map, or our map is a subsection of the world. MapProjection can clip those cases, using
the a
bounding box of min and max coordinates.</p>
<p>Coordinates:
<strong id="map_coords_1"></strong>
</p>
<div class="map-container" id="mapContainerClipped">
<img src="../assets/maps/pixabay/europe.jpg" id="map_image_1" alt="Image is missing." width="512">
</div>
<script class="doctest">
//Same procedure as above, just add a clipping parameter to the MapProjection object.
let europe = new MapProjection(new Projection.Mercator(), {
clip: {
min: { x: 32.863294, y: -18.58 },
max: { x: 57.467973, y: 44.277158 }
}
})
//Same as above
for (let coordinates of Object.values(europeanCapitalCities)) {
let pixelPosition = europe.toPixel(coordinates)
placeMarker(mapContainerClipped, pixelPosition)
}
</script>
<script>
printCoordinates(map_image_1, germany, map_coords_1)
</script>
<h2>Translated Map</h2>
<p>Maps can be also translated, if the whole world is shown and clipping is not an option.</p>
<p>Coordinates:
<strong id="map_coords_2"></strong>
</p>
<div id="map_image_2" class="map-container"">
</div>
<script class=" doctest">
const size = 256
// Fake offset by using the old map projection.
let translation = squared_world.toPixel({ x: 90-10, y: -140 })
console.log(translation)
//This map is clipped at the bottom
// And also translated in hoizontal direction.
// The translate option corrects that.
let translated_world = new MapProjection(new Projection.Mercator(), {
translate: { x: -10, y: 40 },
})
console.log(translation)
Object.assign(map_image_2.style, {
width: size + "px",
height: size + "px",
backgroundImage: "url(../assets/maps/osm/0/0/0.png)",
backgroundColor: "red",
backgroundPosition: translation.x * size + "px " +translation.y * size + "px"
})
//Same as above
for (let coordinates of Object.values(capitals)) {
let position = translated_world.toPixel(coordinates)
placeMarker(map_image_2, position)
}
</script>
<script>
map_image_2.addEventListener("mousemove", (event) => {
let map = map_image_2
console.log(event.offsetX / map.width)
let coords = translated_world.toCoordinates({ x: event.offsetX / map.offsetWidth, y: event.offsetY / map.offsetHeight })
map_coords_2.innerHTML = "Lat: " + coords.x.toFixed(4) + " Lng: " + coords.y.toFixed(4)
})
</script>
</body>
</html>