Last active
November 4, 2018 13:02
-
-
Save linquize/41e62921379b96d39c6ec1bf0cf695c4 to your computer and use it in GitHub Desktop.
OpenStreetMap Filtered Changesets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>Filtered Changesets | OpenStreetMap</title> | |
<link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css" /> | |
<script type="text/javascript" src="node_modules/leaflet/dist/leaflet.js"></script> | |
<script type="text/javascript" src="node_modules/moment/min/moment.min.js"></script> | |
<style type="text/css"> | |
body { | |
font-family: 'Helvetica Neue',Arial,sans-serif; | |
} | |
#root { | |
position: absolute; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
} | |
#sidebar > div { | |
position: relative; | |
float: left; | |
clear: both; | |
width: 100%; | |
} | |
#sidebar h2 { | |
font-size: 16px; | |
font-weight: 600; | |
padding: 0px 20px 0px; | |
} | |
#changesets { | |
padding: 0; | |
} | |
#changesets li { | |
list-style: none; | |
cursor: pointer; | |
font-size: 12px; | |
padding: 15px 20px; | |
border-bottom: 1px dotted gray; | |
} | |
#changesets li:hover { | |
background-color: lightyellow; | |
} | |
#changesets li a { | |
text-decoration: none; | |
color: black; | |
} | |
#changesets li .time { | |
text-decoration: underline dotted; | |
} | |
#changesets li .user { | |
text-decoration: underline; | |
color: blue; | |
} | |
#changesets li .count { | |
float: right; | |
color: green; | |
} | |
#changesets li .id { | |
font-style: italic; | |
} | |
#sidebar { | |
float: left; | |
width: 350px; | |
height: 100%; | |
position: relative; | |
overflow-x: hidden; | |
overflow-y: auto; | |
} | |
#mapid { | |
height: 100%; | |
overflow: hidden; | |
} | |
@media screen and (max-width: 700px) { | |
#sidebar { | |
width: 300px; | |
height: 50%; | |
} | |
#changesets li { | |
padding: 5px 20px; | |
} | |
#mapid { | |
height: 50%; | |
width: 100%; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="root"> | |
<div id="sidebar"> | |
<div> | |
<h2>Changesets</h2> | |
<ol id="changesets"> | |
</ol> | |
</div> | |
</div> | |
<div id="mapid"></div> | |
</div> | |
<template id="changeset-template"> | |
<li> | |
<div class="comment"><a href="https://www.openstreetmap.org/changeset/"></a></div> | |
<div><span class="time"></span> by <a class="user" href="https://www.openstreetmap.org/user/"></a><span class="count"></span></div> | |
<div class="id"></div> | |
</li> | |
</template> | |
<script type="text/javascript"> | |
let mymap = L.map('mapid').setView([22.360000, 114.100000], 11); | |
let tileUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; | |
L.tileLayer(tileUrl, { | |
maxZoom: 19, | |
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors', | |
}).addTo(mymap); | |
L.control.scale().addTo(mymap); | |
</script> | |
<script type="text/javascript"> | |
function pointInPolygon(point, vs) { | |
// https://github.com/substack/point-in-polygon | |
// ray-casting algorithm based on | |
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html | |
let x = point[0], y = point[1]; | |
let inside = false; | |
for (let i = 0, j = vs.length - 1; i < vs.length; j = i++) { | |
let xi = vs[i][0], yi = vs[i][1]; | |
let xj = vs[j][0], yj = vs[j][1]; | |
let intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); | |
if (intersect) inside = !inside; | |
} | |
return inside; | |
}; | |
</script> | |
<script type="text/javascript"> | |
const clipPoly = [ | |
[113.865, 22.334], | |
[113.866, 22.432], | |
[113.946, 22.476], | |
[113.993, 22.514], | |
[114.001, 22.514], | |
[114.014, 22.505], | |
[114.026, 22.511], | |
[114.037, 22.51], | |
[114.051, 22.506], | |
[114.053, 22.507], | |
[114.055, 22.515], | |
[114.062, 22.52], | |
[114.071, 22.522], | |
[114.075, 22.533], | |
[114.083, 22.536], | |
[114.086, 22.54], | |
[114.094, 22.541], | |
[114.098, 22.538], | |
[114.105, 22.539], | |
[114.11, 22.537], | |
[114.112, 22.534], | |
[114.113, 22.537], | |
[114.118, 22.538], | |
[114.119, 22.541], | |
[114.129, 22.546], | |
[114.134, 22.546], | |
[114.138, 22.548], | |
[114.145, 22.546], | |
[114.149, 22.558], | |
[114.154, 22.559], | |
[114.16, 22.566], | |
[114.178, 22.564], | |
[114.18, 22.563], | |
[114.181, 22.559], | |
[114.19, 22.559], | |
[114.195, 22.561], | |
[114.204, 22.56], | |
[114.21, 22.561], | |
[114.214, 22.559], | |
[114.219, 22.56], | |
[114.228, 22.553], | |
[114.231, 22.548], | |
[114.234, 22.554], | |
[114.275, 22.569], | |
[114.333, 22.572], | |
[114.436, 22.566], | |
[114.459, 22.547], | |
[114.459, 22.47], | |
[114.506, 22.367], | |
[114.506, 22.146], | |
[114.502, 22.144], | |
[114.285, 22.144], | |
[114.256, 22.135], | |
[114.253, 22.135], | |
[114.235, 22.144], | |
[113.941, 22.144], | |
[113.925, 22.133], | |
[113.894, 22.139], | |
[113.83, 22.18], | |
[113.813, 22.215], | |
[113.813, 22.219], | |
[113.836, 22.271], | |
[113.844, 22.276], | |
[113.865, 22.334] | |
]; | |
const min_lon = 113.8197, min_lat = 22.1378, max_lon = 114.5023, max_lat = 22.5684; | |
const changesetUrl = `https://www.openstreetmap.org/api/0.6/changesets?bbox=${min_lon},${min_lat},${max_lon},${max_lat}`; | |
fetch(changesetUrl) | |
.then(a => a.text()) | |
.then(a => new DOMParser().parseFromString(a, "application/xml")) | |
.then(dom => { | |
let csList = document.getElementById('changesets'); | |
let changesets = dom.querySelectorAll('changeset'); | |
let filtered = []; | |
for (let changeset of changesets) { | |
let cs_min_lon = parseFloat(changeset.getAttribute('min_lon')); | |
let cs_min_lat = parseFloat(changeset.getAttribute('min_lat')); | |
let cs_max_lon = parseFloat(changeset.getAttribute('max_lon')); | |
let cs_max_lat = parseFloat(changeset.getAttribute('max_lat')); | |
if (cs_min_lon < min_lon) continue; | |
if (cs_min_lat < min_lat) continue; | |
if (cs_max_lon > max_lon) continue; | |
if (cs_max_lat > max_lat) continue; | |
if (!pointInPolygon([cs_min_lon, cs_min_lat], clipPoly)) continue; | |
if (!pointInPolygon([cs_max_lon, cs_max_lat], clipPoly)) continue; | |
let template = document.getElementById('changeset-template'); | |
let row = document.importNode(template.content, true); | |
let li = row.querySelector('li'); | |
let commentTag = changeset.querySelector("tag[k='comment']"); | |
li.querySelector('.comment a').innerText = commentTag ? commentTag.getAttribute('v') : '(No Comment)'; | |
li.querySelector('.comment a').href += changeset.getAttribute('id'); | |
let time = changeset.getAttribute('closed_at'); | |
li.querySelector('.time').innerText = time ? moment(time).format('YYYY-MM-DDTHH:mm:ss') : '(Unknwon Time)'; | |
li.querySelector('.user').innerText = changeset.getAttribute('user'); | |
li.querySelector('.user').href += changeset.getAttribute('user'); | |
li.querySelector('.count').innerText = 'x' + changeset.getAttribute('changes_count'); | |
li.querySelector('.id').innerText = '#' + changeset.getAttribute('id'); | |
li.addEventListener('mouseover', e => e.target.leafletRect = L.rectangle([[cs_min_lat, cs_min_lon], [cs_max_lat, cs_max_lon]], { color: "#ff7800", weight: 2}).addTo(mymap)); | |
li.addEventListener('mouseout', e => e.target.leafletRect ? e.target.leafletRect.removeFrom(mymap) : null); | |
csList.appendChild(row); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment