You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
monero.fail/xmrnodes/templates/map.html

187 lines
6.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<link rel="shortcut icon" href="/static/favicon.ico" type="image/x-icon" />
<meta property="fb:app_id" content="0" />
<meta property="og:image" content="https://www.getmonero.org/press-kit/symbols/monero-symbol-on-white-480.png" />
<meta property="og:description" content="xmrnodes" />
<meta property="og:url" content="http://localhost" />
<meta property="og:title" content="XMR Nodes" />
<meta property="og:type" content="website" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#ffffff">
<meta name="apple-mobile-web-app-title" content="XMR Nodes">
<meta name="application-name" content="XMR Nodes">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="keywords" content="wownero, monero, xmr, bitmonero, cryptocurrency">
7 months ago
<link rel="preload stylesheet" href="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<link rel="preload stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" type="text/css">
<style>
.map {
height: 600px;
margin: 2em;
padding: 0;
}
.popover-body {
min-width: 276px;
}
.center.info {
width: 50%;
margin: auto;
padding: 2em;
}
</style>
<script defer src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder"></script>
<script defer src="//cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
<script defer src="//code.jquery.com/jquery-3.5.1.min.js"></script>
<script defer src="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
<title>XMR Nodes</title>
</head>
<body>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul class="flashes pure-u-1 center">
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
<div class="center info">
<p>Recent Peers: {{ recent_peers }}</p>
<p>Source Node: {{ source_node }}</p>
<p>
This is not a full representation of the entire Monero network,
just a look into the peers being recursively crawled from the source node ({{ source_node }}).
7 months ago
New peers are searched every hour and unresponsive nodes are removed.
</p>
<br>
<a href="/">Go home</a>
</div>
<div id="loadingContainer" style="width: 100%; text-align: center;">
<h1>Loading map... <span id="loadProgress"></span></h1>
<img id="loading" src="/static/images/helping.gif" style="width: 30%;" />
7 months ago
</div>
<div id="map" class="map"></div>
<div id="popup" class="popup" title="Welcome to OpenLayers"></div>
<script>
async function fetchWithDelay(total, delayMs) {
for(let i=0; i < total + 1; i++) {
document.getElementById('loadProgress').innerHTML = `%${Math.round(i / total * 100, 2)}`;
try {
await fetch(`?fetch=1&offset=${i}`)
.then((res) => res.json())
.then((d) => {
for (var url in d.peers) {
let peer = d.peers[url];
var feature = new ol.Feature(
new ol.geom.Point(ol.proj.transform([peer.lon, peer.lat], 'EPSG:4326', 'EPSG:3857'))
);
feature.description = [
`Node ${url}`,
`Last Seen ${peer.last_seen}`
];
feature.setStyle(new ol.style.Style({
image: new ol.style.Circle({
radius: 6,
fill: new ol.style.Fill({
color: peer.rgba,
}),
stroke: new ol.style.Stroke({
color: '#fff',
width: 1
})
})
}));
markerLayer.getSource().addFeature(feature);
}
})
} catch (err) {
console.error(`Error on request ${i}`);
}
}
// Remove loader and show map
document.getElementById('loadingContainer').remove();
document.getElementById('map').style['opacity'] = 1;
}
async function loadMap() {
7 months ago
// Marker layer
markerLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [],
projection: 'EPSG:3857'
})
});
7 months ago
// Create the map
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
preload: 4
7 months ago
}),
markerLayer
],
view: new ol.View({
center: ol.proj.fromLonLat([0, 25]),
zoom: 1
})
});
const res = await fetch('?fetch=1')
.then((res) => res.json())
console.log(`Found ${res.total} pages of peers to fetch`)
fetchWithDelay(res.total);
7 months ago
// Setup popup
var popup = new ol.Overlay({
element: $('#popup')[0],
});
map.addOverlay(popup);
7 months ago
// Show details on each pixel
map.on("click", function(e) {
var element = popup.getElement();
$(element).popover('dispose')
map.forEachFeatureAtPixel(e.pixel, function (feature, layer) {
7 months ago
var coordinate = e.coordinate;
$(element).popover('dispose');
popup.setPosition(coordinate);
element.title = feature.description[0]
$(element).popover({
container: element,
placement: 'top',
animation: false,
html: true,
content: '<p>' + feature.description[1] + '</p>',
});
$(element).popover('show');
});
7 months ago
});
}
// Wait for full load
addEventListener("DOMContentLoaded", (event) => {
document.getElementById('map').style['opacity'] = 0;
setTimeout(function() {
loadMap();
}, 1500);
});
</script>
</body>
</html>