bbox2heatmap
Version:
Crawling Flickr's geotagged photographs and drawing a heatmap
415 lines (402 loc) • 19.4 kB
HTML
<html lang="ja">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<title>Heatmap Viewer for Flickr Geotagged Photographs</title>
<style>
body,
html {
margin: 0;
padding: 0;
height: 100%;
}
body {
font-family: sans-serif;
}
body * {
font-weight: 200;
}
h1 {
position: absolute;
background: white;
padding: 10px;
}
#map {
height: 100%;
}
#thumb {
border: 3px solid black;
z-index: 10000;
width: 81px;
height: 81px;
background-color: beige;
position: absolute;
top: 100%;
left: 0px;
margin-top: -81px;
}
h1 {
position: absolute;
background: black;
color: white;
padding: 10px;
font-weight: 200;
z-index: 10000;
}
#btn {
position: absolute;
background: black;
color: white;
padding: 10px;
font-weight: 200;
z-index: 10000;
left: 100%;
width: 300px;
margin-left: -300px;
}
/*Thanks https://gist.github.com/comp615/2288108*/
.leaflet-div-icon {
background: transparent ;
border: none ;
color: white ;
}
.leaflet-marker-icon .number {
position: relative;
top: -37px;
font-size: 12px;
width: 25px;
text-align: center;
}
</style>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<!--link rel="stylesheet" href="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/css/bootstrap.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/twbs/bootstrap/v4-dev/dist/js/bootstrap.js"></script-->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.8.0/leaflet.min.js"
integrity="sha512-TL+GX2RsOUlTndpkgHVnSQ9r6zldqHzfyECrdabkpucdFroZ3/HAhMmP2WYaPjsJCoot+0McmdPOLjmmicG9qg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.8.0/leaflet.min.css"
integrity="sha512-oIQ0EBio8LJupRpgmDsIsvm0Fsr6c3XNHLB7at5xb+Cf6eQuCX9xuX8XXGRIcokNgdqL1ms7nqbQ6ryXMGxXpg=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<!--link rel="stylesheet" href="https://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" /-->
<!--script src="https://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script-->
<!--script src="lib/heatmap.js"></script-->
<script
src="https://cdnjs.cloudflare.com/ajax/libs/heatmap.js/2.0.0/heatmap.min.js"
integrity="sha512-FpvmtV53P/z7yzv1TAIVH7PNz94EKXs5aV6ts/Zi+B/VeGU5Xwo6KIbwpTgKc0d4urD/BtkK50IC9785y68/AA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<!--script src="lib/leaflet-heatmap.js"></script-->
<script src="https://cdn.jsdelivr.net/npm/leaflet-heatmap@1.0.0/leaflet-heatmap.min.js"></script>
</head>
<body>
<div id="btn">
<div id="tag"></div>
</div>
<div id="thumb"><img /></div>
<div id="map"></div>
<script>
const dataset={bbox2heatmap0result};
const search={bbox2heatmap0search};
const bboxraw={bbox2heatmap0bbox};
</script>
<script>
// Thanks https://gist.github.com/comp615/2288108
let photos = [];
let photoIdx = 0;
let photoMarker = null;
let map;
function changePhoto() {
if (photos.length <= photoIdx) {
photoIdx = 0;
}
if (photoMarker != null) {
map.removeLayer(photoMarker);
}
$('#thumb>img').attr('src', photos[photoIdx++].url);
photoMarker = L.marker([photos[photoIdx++].lat, photos[photoIdx++].lng]).addTo(map);
setTimeout(changePhoto, 1000);
}
L.NumberedDivIcon = L.Icon.extend({
options: {
// EDIT THIS TO POINT TO THE FILE AT http://www.charliecroom.com/marker_hole.png (or your own marker)
iconUrl: 'lib/marker.png',
number: '',
shadowUrl: null,
iconSize: new L.Point(25, 41),
iconAnchor: new L.Point(13, 41),
popupAnchor: new L.Point(0, -33),
className: 'leaflet-div-icon',
},
createIcon: function () {
var div = document.createElement('div');
var img = this._createImg(this.options['iconUrl']);
var numdiv = document.createElement('div');
numdiv.setAttribute('class', 'number');
numdiv.innerHTML = this.options['number'] || '';
div.appendChild(img);
div.appendChild(numdiv);
this._setIconStyles(div, 'icon');
return div;
},
//you could change this to add a shadow like in the normal marker if you really wanted
createShadow: function () {
return null;
},
});
var layer;
var cells = 50;
window.onload = function () {
const bbox = [
[bboxraw[1], bboxraw[0]],
[bboxraw[3], bboxraw[2]],
];
console.log(search, bbox);
var baseLayer = L.tileLayer('https://{{s}}.tile.openstreetmap.org/{{z}}/{{x}}/{{y}}.png', {
attribution: 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://cloudmade.com">CloudMade</a>',
maxZoom: 18,
});
var src = {
max: 45,
data: [],
};
//var dataset = JSON.parse(e.target.result);
var east = Math.max(dataset.bbox[0], dataset.bbox[2]);
var west = Math.min(dataset.bbox[0], dataset.bbox[2]);
var north = Math.max(dataset.bbox[1], dataset.bbox[3]);
var south = Math.min(dataset.bbox[1], dataset.bbox[3]);
var center = { lat: west + (east - west) / 2, lng: south + (north - south) / 2 };
var grid = {};
var track = {};
if (dataset.track) {
dataset.track.every(function (item) {
track[item] = [];
return true;
});
}
document.getElementById('tag').innerHTML = 'Search: ' + dataset.search;
var range = Math.min(north - south, east - west) / cells;
dataset.data.forEach(function (item) {
//console.log(item);
photos.push({
url: item.url_sq,
lat: item.latitude,
lng: item.longitude,
});
if (item.latitude && item.longitude) {
var lat = parseFloat(item.latitude);
var lng = parseFloat(item.longitude);
var sn = Math.floor((lat - south) / range);
var we = Math.floor((lng - west) / range);
if (grid[sn + '.' + we]) {
grid[sn + '.' + we]++;
} else {
grid[sn + '.' + we] = 1;
}
var d = {
lat: lat,
lng: lng,
count: 1,
};
if (dataset.track) {
Object.keys(track).every(function (id) {
if (id == item.owner) {
track[id].push(item);
return false;
} else {
return true;
}
});
}
src.data.push(d);
}
});
var n = [];
for (var idx in grid) {
n.push(grid[idx]);
}
n = n.sort(function cp(val1, val2) {
return val2 - val1;
});
//console.log(track);
if (dataset.track) {
Object.keys(track).every(function (id) {
var traj = track[id].sort(function (p1, p2) {
return p1.datetaken - p2.datetaken;
});
traj.every(function (item, n) {
var marker = new L.Marker(new L.LatLng(parseFloat(item.latitude), parseFloat(item.longitude)), {
icon: new L.NumberedDivIcon({ number: n + 1 }),
});
marker.on('click', function () {
//console.log(item.datetaken + '\t' + item.url_z);
});
marker.addTo(map);
return true;
});
return true;
});
}
src.max = Math.round(n[Math.round(n.length / 10)]);
var cfg = {
radius: range,
maxOpacity: 0.8,
scaleRadius: true,
useLocalExtrema: false,
latField: 'lat',
lngField: 'lng',
valueField: 'count',
};
console.log('[Draw heatmap] max=' + src.max + ' ,range=' + range);
var heatmapLayer = new HeatmapOverlay(cfg);
heatmapLayer.setData(src);
map = new L.Map('map', {
center: new L.LatLng(center.lat, center.lng),
zoom: 4,
layers: [baseLayer, heatmapLayer],
});
console.log('BBOX', JSON.stringify(bbox));
map.fitBounds(bbox);
map.on('zoomend', function () {
//console.log("zoom");
map.removeLayer(heatmapLayer);
var east = Math.max(dataset.bbox[0], dataset.bbox[2]);
var west = Math.min(dataset.bbox[0], dataset.bbox[2]);
var north = Math.max(dataset.bbox[1], dataset.bbox[3]);
var south = Math.min(dataset.bbox[1], dataset.bbox[3]);
var rangeDataset = Math.min(north - south, east - west) / cells;
var b = map.getBounds();
var rangeMap = Math.min(b.getNorth() - b.getSouth(), b.getEast() - b.getWest()) / cells;
var new_cfg = {
radius: Math.min(rangeDataset, rangeMap),
maxOpacity: 0.8,
scaleRadius: true,
useLocalExtrema: true,
latField: 'lat',
lngField: 'lng',
valueField: 'count',
};
heatmapLayer = new HeatmapOverlay(new_cfg);
map.addLayer(heatmapLayer);
heatmapLayer.setData(src);
});
changePhoto();
};
/*
document.getElementById('files').addEventListener('change', function (evt) {
var reader = new FileReader();
reader.onload = function (e) {
map.removeLayer(layer);
var src = {
max: 45,
data: [],
};
var dataset = JSON.parse(e.target.result);
var east = Math.max(dataset.bbox[0], dataset.bbox[2]);
var west = Math.min(dataset.bbox[0], dataset.bbox[2]);
var north = Math.max(dataset.bbox[1], dataset.bbox[3]);
var south = Math.min(dataset.bbox[1], dataset.bbox[3]);
var cells = 50;
var grid = {};
var track = {};
if (dataset.track) {
dataset.track.every(function (item) {
track[item] = [];
return true;
});
}
document.getElementById('tag').innerHTML = 'Search: ' + dataset.search;
var range = Math.min(north - south, east - west) / cells;
dataset.data.forEach(function (item) {
if (item.latitude && item.longitude) {
var lat = parseFloat(item.latitude);
var lng = parseFloat(item.longitude);
var sn = Math.floor((lat - south) / range);
var we = Math.floor((lng - west) / range);
if (grid[sn + '.' + we]) {
grid[sn + '.' + we]++;
} else {
grid[sn + '.' + we] = 1;
}
var d = {
lat: lat,
lng: lng,
count: 1,
};
if (dataset.track) {
Object.keys(track).every(function (id) {
if (id == item.owner) {
track[id].push(item);
return false;
} else {
return true;
}
});
}
src.data.push(d);
}
});
var n = [];
for (var idx in grid) {
n.push(grid[idx]);
}
n = n.sort(function cp(val1, val2) {
return val2 - val1;
});
console.log(track);
if (dataset.track) {
Object.keys(track).every(function (id) {
var traj = track[id].sort(function (p1, p2) {
return p1.datetaken - p2.datetaken;
});
traj.every(function (item, n) {
var marker = new L.Marker(new L.LatLng(parseFloat(item.latitude), parseFloat(item.longitude)), {
icon: new L.NumberedDivIcon({ number: n + 1 }),
});
marker.on('click', function () {
console.log(item.datetaken + '\t' + item.url_z);
});
marker.addTo(map);
return true;
});
return true;
});
}
src.max = Math.round(n[Math.round(n.length / 10)]);
var cfg = {
radius: range,
maxOpacity: 0.8,
scaleRadius: true,
useLocalExtrema: false,
latField: 'lat',
lngField: 'lng',
valueField: 'count',
};
console.log('[Draw heatmap] max=' + src.max + ' ,range=' + range);
layer = new HeatmapOverlay(cfg);
map.addLayer(layer);
layer.setData(src);
map.fitBounds([
[dataset.bbox[1], dataset.bbox[0]],
[dataset.bbox[3], dataset.bbox[2]],
]);
};
reader.readAsText(evt.target.files[0]);
});
*/
</script>
</body>
</html>