Skip to content

Instantly share code, notes, and snippets.

@NelsonMinar
Last active October 9, 2022 05:39
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save NelsonMinar/6600524 to your computer and use it in GitHub Desktop.
Save NelsonMinar/6600524 to your computer and use it in GitHub Desktop.
GTA V Map Viewer
Tools for making a very simple web slippy map of Grand Theft Auto V maps.
By Nelson Minar <nelson@monkey.org>
I don't want to host this map myself because of copyright concerns.
No support provided for this code, just hoping it's a useful guide for
someone to roll their own amp.
maketiles.sh runs gdal2tiles.py to slice up the source image into tiles.
map.html is a simple Leaflet / web map.
You're on your own for finding the map image source.
See this tutorial for more info on gdal2tiles.py
http://build-failed.blogspot.com/2012/11/zoomable-image-with-leaflet.html
(function(window) {
var HAS_HASHCHANGE = (function() {
var doc_mode = window.documentMode;
return ('onhashchange' in window) &&
(doc_mode === undefined || doc_mode > 7);
})();
L.Hash = function(map) {
this.onHashChange = L.Util.bind(this.onHashChange, this);
if (map) {
this.init(map);
}
};
L.Hash.prototype = {
map: null,
lastHash: null,
parseHash: function(hash) {
if(hash.indexOf('#') === 0) {
hash = hash.substr(1);
}
var args = hash.split("/");
if (args.length == 3) {
var zoom = parseInt(args[0], 10),
lat = parseFloat(args[1]),
lon = parseFloat(args[2]);
if (isNaN(zoom) || isNaN(lat) || isNaN(lon)) {
return false;
} else {
return {
center: new L.LatLng(lat, lon),
zoom: zoom
};
}
} else {
return false;
}
},
formatHash: function(map) {
var center = map.getCenter(),
zoom = map.getZoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
return "#" + [zoom,
center.lat.toFixed(precision),
center.lng.toFixed(precision)
].join("/");
},
init: function(map) {
this.map = map;
// reset the hash
this.lastHash = null;
this.onHashChange();
if (!this.isListening) {
this.startListening();
}
},
remove: function() {
if (this.changeTimeout) {
clearTimeout(this.changeTimeout);
}
if (this.isListening) {
this.stopListening();
}
this.map = null;
},
onMapMove: function() {
// bail if we're moving the map (updating from a hash),
// or if the map is not yet loaded
if (this.movingMap || !this.map._loaded) {
return false;
}
var hash = this.formatHash(this.map);
if (this.lastHash != hash) {
location.replace(hash);
this.lastHash = hash;
}
},
movingMap: false,
update: function() {
var hash = location.hash;
if (hash === this.lastHash) {
return;
}
var parsed = this.parseHash(hash);
if (parsed) {
this.movingMap = true;
this.map.setView(parsed.center, parsed.zoom);
this.movingMap = false;
} else {
this.onMapMove(this.map);
}
},
// defer hash change updates every 100ms
changeDefer: 100,
changeTimeout: null,
onHashChange: function() {
// throttle calls to update() so that they only happen every
// `changeDefer` ms
if (!this.changeTimeout) {
var that = this;
this.changeTimeout = setTimeout(function() {
that.update();
that.changeTimeout = null;
}, this.changeDefer);
}
},
isListening: false,
hashChangeInterval: null,
startListening: function() {
this.map.on("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.addListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
this.hashChangeInterval = setInterval(this.onHashChange, 50);
}
this.isListening = true;
},
stopListening: function() {
this.map.off("moveend", this.onMapMove, this);
if (HAS_HASHCHANGE) {
L.DomEvent.removeListener(window, "hashchange", this.onHashChange);
} else {
clearInterval(this.hashChangeInterval);
}
this.isListening = false;
}
};
L.hash = function(map) {
return new L.Hash(map);
};
L.Map.prototype.addHash = function() {
this._hash = L.hash(this);
};
L.Map.prototype.removeHash = function() {
this._hash.remove();
};
})(window);
#!/bin/bash
gdal2tiles.py -p raster -z 0-5 -w none GTA\ V\ Map.jpg satellite
gdal2tiles.py -p raster -z 0-5 -w none GTA\ V\ Map\ 2.jpg atlas
gdal2tiles.py -p raster -z 0-5 -w none GTA\ V\ Map\ 3.jpg road
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0"/>
<title>Leaflet template</title>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
<!--[if lte IE 8]>
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.ie.css" />
<![endif]-->
<script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>
<script src="leaflet-hash.js"></script>
<style type="text/css">
html, body { height: 100% }
#map { min-height: 100%; }
body {
margin: 0;
font-family: Helvetica, Arial, sans-serif; font-size: 12px;
overflow: hidden;
background-color: #f00;
}
</style>
</head><body>
<div id="map"></div>
<script type="text/javascript">
var atlas = L.tileLayer('atlas/{z}/{x}/{y}.png', {
attribution: '<a href="http://www.rockstargames.com/V/">Grand Theft Auto V</a>, web version quickly done by <a href="http://www.somebits.com/weblog/">Nelson Minar</a>',
minZoom: 1, maxZoom: 5, noWrap: true, tms: true
});
var satellite = L.tileLayer('satellite/{z}/{x}/{y}.png', {
attribution: '<a href="http://www.rockstargames.com/V/">Grand Theft Auto V</a>, web version quickly done by <a href="http://www.somebits.com/weblog/">Nelson Minar</a>',
minZoom: 1, maxZoom: 5, noWrap: true, tms: true
});
var road = L.tileLayer('road/{z}/{x}/{y}.png', {
attribution: '<a href="http://www.rockstargames.com/V/">Grand Theft Auto V</a>, web version quickly done by <a href="http://www.somebits.com/weblog/">Nelson Minar</a>',
minZoom: 1, maxZoom: 5, noWrap: true, tms: true
});
var map = L.map('map', {layers: satellite});
var hash = new L.Hash(map);
map.setView([0, 0], 2);
L.control.layers({"Satellite": satellite, "Atlas": atlas, "Road": road}, {}).addTo(map);
satellite.bringToFront();
</script>
</body></html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment