New UI control to toggle signposts on/off based on their content.
Pretty substantial javascript refactoring: * All javascript is now in funtions.js. There is no javascript at all in index.html * Configuration options moved from template.html to config.js template.html moved to web_assets/index.html config.js allows you to specify pattern-label pairs. Each label will be added to an on-screen "signposts" control. Clicking the checkbox by each label will show/hide any signposts that match the pattern attached to that label. config.js has some examples. TODO: * The signposts control needs better styling. * The new javascript needs testing in IE. Seems ok in Chome and FF. These large changes may be hard to merge if you have non-trivial JS changes to template.html locally. Apologies in advance
This commit is contained in:
28
config.js
Normal file
28
config.js
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
var config = {
|
||||
path: 'tiles',
|
||||
fileExt: '{imgformat}',
|
||||
tileSize: 384,
|
||||
defaultZoom: 1,
|
||||
maxZoom: {maxzoom},
|
||||
cacheMinutes: 0, // Change this to have browsers automatically request new images every x minutes
|
||||
debug: false
|
||||
};
|
||||
|
||||
|
||||
// define a list of pattern-label pairs. Each label will appear
|
||||
// in the 'Signposts' control, allowing your users to quickly enable
|
||||
// or disable certain labels. See below for some examples:
|
||||
var signGroups = {
|
||||
// "Directions": /^#Direction/i,
|
||||
// "Big Dig": /big\s*dig/i,
|
||||
// "Warnings": /warning/i,
|
||||
};
|
||||
|
||||
// Please leave the following variables here:
|
||||
var markerCollection = {}; // holds groups of markers
|
||||
|
||||
var map;
|
||||
|
||||
var markersInit = false;
|
||||
var regionsInit = false;
|
||||
21
quadtree.py
21
quadtree.py
@@ -125,19 +125,20 @@ class QuadtreeGen(object):
|
||||
complete, total, level, self.p))
|
||||
|
||||
def write_html(self, skipjs=False):
|
||||
"""Writes out index.html, marker.js, and region.js"""
|
||||
"""Writes out config.js, marker.js, and region.js
|
||||
Copies web assets into the destdir"""
|
||||
zoomlevel = self.p
|
||||
imgformat = self.imgformat
|
||||
templatepath = os.path.join(util.get_program_path(), "template.html")
|
||||
configpath = os.path.join(util.get_program_path(), "config.js")
|
||||
|
||||
html = open(templatepath, 'r').read()
|
||||
html = html.replace(
|
||||
config = open(configpath, 'r').read()
|
||||
config = config.replace(
|
||||
"{maxzoom}", str(zoomlevel))
|
||||
html = html.replace(
|
||||
config = config.replace(
|
||||
"{imgformat}", str(imgformat))
|
||||
|
||||
with open(os.path.join(self.destdir, "index.html"), 'w') as output:
|
||||
output.write(html)
|
||||
with open(os.path.join(self.destdir, "config.js"), 'w') as output:
|
||||
output.write(config)
|
||||
|
||||
# Write a blank image
|
||||
blank = Image.new("RGBA", (1,1))
|
||||
@@ -181,11 +182,11 @@ class QuadtreeGen(object):
|
||||
|
||||
def _get_cur_depth(self):
|
||||
"""How deep is the quadtree currently in the destdir? This glances in
|
||||
index.html to see what maxZoom is set to.
|
||||
config.js to see what maxZoom is set to.
|
||||
returns -1 if it couldn't be detected, file not found, or nothing in
|
||||
index.html matched
|
||||
config.js matched
|
||||
"""
|
||||
indexfile = os.path.join(self.destdir, "index.html")
|
||||
indexfile = os.path.join(self.destdir, "config.js")
|
||||
if not os.path.exists(indexfile):
|
||||
return -1
|
||||
matcher = re.compile(r"maxZoom:\s*(\d+)")
|
||||
|
||||
276
template.html
276
template.html
@@ -1,276 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<script type="text/javascript" src="markers.js"></script>
|
||||
<script type="text/javascript" src="regions.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="http://maps.google.com/maps/api/js?sensor=false">
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var config = {
|
||||
path: 'tiles',
|
||||
fileExt: '{imgformat}',
|
||||
tileSize: 384,
|
||||
defaultZoom: 1,
|
||||
maxZoom: {maxzoom},
|
||||
cacheMinutes: 0, // Change this to have browsers automatically request new images every x minutes
|
||||
debug: false
|
||||
};
|
||||
|
||||
// our custom projection maps Latitude to Y, and Longitude to X as normal,
|
||||
// but it maps the range [0.0, 1.0] to [0, tileSize] in both directions
|
||||
// so it is easier to position markers, etc. based on their position
|
||||
// (find their position in the lowest-zoom image, and divide by tileSize)
|
||||
function MCMapProjection() {
|
||||
this.inverseTileSize = 1.0 / config.tileSize;
|
||||
}
|
||||
|
||||
MCMapProjection.prototype.fromLatLngToPoint = function(latLng) {
|
||||
var x = latLng.lng() * config.tileSize;
|
||||
var y = latLng.lat() * config.tileSize;
|
||||
return new google.maps.Point(x, y);
|
||||
};
|
||||
|
||||
MCMapProjection.prototype.fromPointToLatLng = function(point) {
|
||||
var lng = point.x * this.inverseTileSize;
|
||||
var lat = point.y * this.inverseTileSize;
|
||||
return new google.maps.LatLng(lat, lng);
|
||||
};
|
||||
|
||||
// helper to get map LatLng from world coordinates
|
||||
// takes arguments in X, Y, Z order
|
||||
// (arguments are *out of order*, because within the function we use
|
||||
// the axes like the rest of Minecraft Overviewer -- with the Z and Y
|
||||
// flipped from normal minecraft usage.)
|
||||
function fromWorldToLatLng(x, z, y)
|
||||
{
|
||||
// the width and height of all the highest-zoom tiles combined, inverted
|
||||
var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom));
|
||||
|
||||
// This information about where the center column is may change with a different
|
||||
// drawing implementation -- check it again after any drawing overhauls!
|
||||
|
||||
// point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2)
|
||||
// so the Y coordinate is at 0.5, and the X is at 0.5 - ((tileSize / 2) / (tileSize * 2^maxZoom))
|
||||
// or equivalently, 0.5 - (1 / 2^(maxZoom + 1))
|
||||
var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1));
|
||||
var lat = 0.5;
|
||||
|
||||
// the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py"
|
||||
|
||||
// each block on X axis adds 12px to x and subtracts 6px from y
|
||||
lng += 12 * x * perPixel;
|
||||
lat -= 6 * x * perPixel;
|
||||
|
||||
// each block on Y axis adds 12px to x and adds 6px to y
|
||||
lng += 12 * y * perPixel;
|
||||
lat += 6 * y * perPixel;
|
||||
|
||||
// each block down along Z adds 12px to y
|
||||
lat += 12 * (128 - z) * perPixel;
|
||||
|
||||
// add on 12 px to the X coordinate and 18px to the Y to center our point
|
||||
lng += 12 * perPixel;
|
||||
lat += 18 * perPixel;
|
||||
|
||||
return new google.maps.LatLng(lat, lng);
|
||||
}
|
||||
|
||||
var MCMapOptions = {
|
||||
getTileUrl: function(tile, zoom) {
|
||||
var url = config.path;
|
||||
if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) {
|
||||
url += '/blank';
|
||||
} else if(zoom == 0) {
|
||||
url += '/base';
|
||||
} else {
|
||||
for(var z = zoom - 1; z >= 0; --z) {
|
||||
var x = Math.floor(tile.x / Math.pow(2, z)) % 2;
|
||||
var y = Math.floor(tile.y / Math.pow(2, z)) % 2;
|
||||
url += '/' + (x + 2 * y);
|
||||
}
|
||||
}
|
||||
url = url + '.' + config.fileExt;
|
||||
if(config.cacheMinutes > 0) {
|
||||
var d = new Date();
|
||||
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
||||
}
|
||||
return(url);
|
||||
},
|
||||
tileSize: new google.maps.Size(config.tileSize, config.tileSize),
|
||||
maxZoom: config.maxZoom,
|
||||
minZoom: 0,
|
||||
isPng: !(config.fileExt.match(/^png$/i) == null)
|
||||
};
|
||||
|
||||
var MCMapType = new google.maps.ImageMapType(MCMapOptions);
|
||||
MCMapType.name = "MC Map";
|
||||
MCMapType.alt = "Minecraft Map";
|
||||
MCMapType.projection = new MCMapProjection();
|
||||
|
||||
function CoordMapType() {
|
||||
}
|
||||
|
||||
function CoordMapType(tileSize) {
|
||||
this.tileSize = tileSize;
|
||||
}
|
||||
|
||||
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
|
||||
var div = ownerDocument.createElement('DIV');
|
||||
div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")";
|
||||
div.innerHTML += "<br />";
|
||||
div.innerHTML += MCMapOptions.getTileUrl(coord, zoom);
|
||||
div.style.width = this.tileSize.width + 'px';
|
||||
div.style.height = this.tileSize.height + 'px';
|
||||
div.style.fontSize = '10';
|
||||
div.style.borderStyle = 'solid';
|
||||
div.style.borderWidth = '1px';
|
||||
div.style.borderColor = '#AAAAAA';
|
||||
return div;
|
||||
};
|
||||
|
||||
var map;
|
||||
|
||||
var markersInit = false;
|
||||
|
||||
function prepareSignMarker(marker, item) {
|
||||
|
||||
var c = "<div class=\"infoWindow\"><img src=\"signpost.png\" /><p>" + item.msg.replace(/\n/g,"<br/>") + "</p></div>";
|
||||
var infowindow = new google.maps.InfoWindow({
|
||||
content: c
|
||||
});
|
||||
google.maps.event.addListener(marker, 'click', function() {
|
||||
infowindow.open(map,marker);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function initMarkers() {
|
||||
if (markersInit) { return; }
|
||||
|
||||
markersInit = true;
|
||||
|
||||
for (i in markerData) {
|
||||
var item = markerData[i];
|
||||
|
||||
// a default:
|
||||
var iconURL = '';
|
||||
|
||||
if (item.type == 'spawn') { iconURL = 'http://google-maps-icons.googlecode.com/files/home.png';}
|
||||
if (item.type == 'sign') { iconURL = 'signpost_icon.png';}
|
||||
|
||||
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
||||
var marker = new google.maps.Marker({
|
||||
position: converted,
|
||||
map: map,
|
||||
title: item.msg,
|
||||
icon: iconURL
|
||||
|
||||
});
|
||||
|
||||
if (item.type == 'sign') {
|
||||
prepareSignMarker(marker, item);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var regionsInit = false;
|
||||
function initRegions() {
|
||||
if (regionsInit) { return; }
|
||||
|
||||
regionsInit = true;
|
||||
|
||||
for (i in regionData) {
|
||||
var region = regionData[i];
|
||||
var converted = new google.maps.MVCArray();
|
||||
for (j in region.path) {
|
||||
var point = region.path[j];
|
||||
converted.push(fromWorldToLatLng(point.x, point.y, point.z));
|
||||
}
|
||||
|
||||
if (region.closed) {
|
||||
new google.maps.Polygon({
|
||||
clickable: false,
|
||||
geodesic: false,
|
||||
map: map,
|
||||
strokeColor: region.color,
|
||||
strokeOpacity: region.opacity,
|
||||
strokeWeight: 2,
|
||||
fillColor: region.color,
|
||||
fillOpacity: region.opacity * 0.25,
|
||||
zIndex: i,
|
||||
paths: converted
|
||||
});
|
||||
} else {
|
||||
new google.maps.Polyline({
|
||||
clickable: false,
|
||||
geodesic: false,
|
||||
map: map,
|
||||
strokeColor: region.color,
|
||||
strokeOpacity: region.opacity,
|
||||
strokeWeight: 2,
|
||||
zIndex: i,
|
||||
path: converted
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
var mapOptions = {
|
||||
zoom: config.defaultZoom,
|
||||
center: new google.maps.LatLng(0.5, 0.5),
|
||||
navigationControl: true,
|
||||
scaleControl: false,
|
||||
mapTypeControl: false,
|
||||
streetViewControl: false,
|
||||
mapTypeId: 'mcmap'
|
||||
};
|
||||
map = new google.maps.Map(document.getElementById("mcmap"), mapOptions);
|
||||
|
||||
if(config.debug) {
|
||||
map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize)));
|
||||
|
||||
google.maps.event.addListener(map, 'click', function(event) {
|
||||
console.log("latLng; " + event.latLng.lat() + ", " + event.latLng.lng());
|
||||
|
||||
var pnt = map.getProjection().fromLatLngToPoint(event.latLng);
|
||||
console.log("point: " + pnt);
|
||||
|
||||
var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom);
|
||||
var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom);
|
||||
console.log("pixel: " + pxx + ", " + pxy);
|
||||
});
|
||||
}
|
||||
|
||||
// Now attach the coordinate map type to the map's registry
|
||||
map.mapTypes.set('mcmap', MCMapType);
|
||||
|
||||
// We can now set the map to use the 'coordinate' map type
|
||||
map.setMapTypeId('mcmap');
|
||||
|
||||
// initialize the markers and regions
|
||||
initMarkers();
|
||||
initRegions();
|
||||
|
||||
var compassDiv = document.createElement('DIV');
|
||||
|
||||
compassDiv.style.padding = '5px';
|
||||
|
||||
var compassImg = document.createElement('IMG');
|
||||
compassImg.src="compass.png";
|
||||
compassDiv.appendChild(compassImg);
|
||||
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv);
|
||||
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="initialize()">
|
||||
<div id="mcmap" style="width:100%; height:100%"></div>
|
||||
</body>
|
||||
</html>
|
||||
372
web_assets/functions.js
Normal file
372
web_assets/functions.js
Normal file
@@ -0,0 +1,372 @@
|
||||
|
||||
function prepareSignMarker(marker, item) {
|
||||
|
||||
var c = "<div class=\"infoWindow\"><img src=\"signpost.png\" /><p>" + item.msg.replace(/\n/g,"<br/>") + "</p></div>";
|
||||
var infowindow = new google.maps.InfoWindow({content: c
|
||||
});
|
||||
google.maps.event.addListener(marker, 'click', function() {
|
||||
infowindow.open(map,marker);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function drawMapControls() {
|
||||
|
||||
// compass rose, in the top right corner
|
||||
var compassDiv = document.createElement('DIV');
|
||||
|
||||
compassDiv.style.padding = '5px';
|
||||
|
||||
var compassImg = document.createElement('IMG');
|
||||
compassImg.src="compass.png";
|
||||
compassDiv.appendChild(compassImg);
|
||||
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(compassDiv);
|
||||
|
||||
|
||||
// signpost display control
|
||||
//
|
||||
|
||||
var signControl = document.createElement("DIV");
|
||||
signControl.id = "signControl"; // let's let a style sheet do most of the styling here
|
||||
|
||||
var controlBorder = document.createElement("DIV");
|
||||
controlBorder.id="top";
|
||||
signControl.appendChild(controlBorder);
|
||||
|
||||
var controlText = document.createElement("DIV");
|
||||
|
||||
controlBorder.appendChild(controlText);
|
||||
|
||||
controlText.innerHTML = "Signposts";
|
||||
|
||||
var dropdownDiv = document.createElement("DIV");
|
||||
|
||||
|
||||
$(controlText).click(function() {
|
||||
$(dropdownDiv).toggle();
|
||||
|
||||
});
|
||||
|
||||
|
||||
dropdownDiv.id="dropDown";
|
||||
signControl.appendChild(dropdownDiv);
|
||||
dropdownDiv.innerHTML="";
|
||||
|
||||
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(signControl);
|
||||
|
||||
|
||||
|
||||
for (label in signGroups) {
|
||||
var n = document.createElement("input");
|
||||
n.type="checkbox";
|
||||
|
||||
$(n).data("label",label);
|
||||
jQuery(n).click(function(e) {
|
||||
var t = $(e.target);
|
||||
jQuery.each(markerCollection[t.data("label")], function(i,elem) {elem.setVisible(e.target.checked);});
|
||||
});
|
||||
|
||||
dropdownDiv.appendChild(n);
|
||||
var textNode = document.createElement("text");
|
||||
textNode.innerHTML = label + "<br/>";
|
||||
dropdownDiv.appendChild(textNode);
|
||||
|
||||
}
|
||||
|
||||
// add "others"
|
||||
var n = document.createElement("input");
|
||||
n.type="checkbox";
|
||||
|
||||
$(n).data("label","__others__");
|
||||
jQuery(n).click(function(e) {
|
||||
var t = $(e.target);
|
||||
jQuery.each(markerCollection[t.data("label")], function(i,elem) {elem.setVisible(e.target.checked);});
|
||||
});
|
||||
|
||||
dropdownDiv.appendChild(n);
|
||||
var textNode = document.createElement("text");
|
||||
textNode.innerHTML = "Others<br/>";
|
||||
dropdownDiv.appendChild(textNode);
|
||||
}
|
||||
|
||||
function initRegions() {
|
||||
if (regionsInit) { return; }
|
||||
|
||||
regionsInit = true;
|
||||
|
||||
for (i in regionData) {
|
||||
var region = regionData[i];
|
||||
var converted = new google.maps.MVCArray();
|
||||
for (j in region.path) {
|
||||
var point = region.path[j];
|
||||
converted.push(fromWorldToLatLng(point.x, point.y, point.z));
|
||||
}
|
||||
|
||||
if (region.closed) {
|
||||
new google.maps.Polygon({clickable: false,
|
||||
geodesic: false,
|
||||
map: map,
|
||||
strokeColor: region.color,
|
||||
strokeOpacity: region.opacity,
|
||||
strokeWeight: 2,
|
||||
fillColor: region.color,
|
||||
fillOpacity: region.opacity * 0.25,
|
||||
zIndex: i,
|
||||
paths: converted
|
||||
});
|
||||
} else {
|
||||
new google.maps.Polyline({clickable: false,
|
||||
geodesic: false,
|
||||
map: map,
|
||||
strokeColor: region.color,
|
||||
strokeOpacity: region.opacity,
|
||||
strokeWeight: 2,
|
||||
zIndex: i,
|
||||
path: converted
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function initMarkers() {
|
||||
if (markersInit) { return; }
|
||||
|
||||
markersInit = true;
|
||||
|
||||
for (i in markerData) {
|
||||
var item = markerData[i];
|
||||
|
||||
// a default:
|
||||
var iconURL = '';
|
||||
if (item.type == 'spawn') {
|
||||
// don't filter spawn, always display
|
||||
|
||||
iconURL = 'http://google-maps-icons.googlecode.com/files/home.png';
|
||||
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
||||
var marker = new google.maps.Marker({position: converted,
|
||||
map: map,
|
||||
title: item.msg,
|
||||
icon: iconURL
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var matched = false;
|
||||
for (label in signGroups) {
|
||||
var pattern = signGroups[label];
|
||||
|
||||
var r = item.msg.match(pattern);
|
||||
if (r) {
|
||||
matched = true;
|
||||
|
||||
if (item.type == 'sign') { iconURL = 'signpost_icon.png';}
|
||||
|
||||
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
||||
var marker = new google.maps.Marker({position: converted,
|
||||
map: map,
|
||||
title: item.msg,
|
||||
icon: iconURL,
|
||||
visible: false
|
||||
});
|
||||
if (markerCollection[label]) {
|
||||
markerCollection[label].push(marker);
|
||||
} else {
|
||||
markerCollection[label] = [marker];
|
||||
}
|
||||
|
||||
if (item.type == 'sign') {
|
||||
prepareSignMarker(marker, item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
// is this signpost doesn't match any of the groups in config.js, add it automatically to the "__others__" group
|
||||
if (item.type == 'sign') { iconURL = 'signpost_icon.png';}
|
||||
|
||||
var converted = fromWorldToLatLng(item.x, item.y, item.z);
|
||||
var marker = new google.maps.Marker({position: converted,
|
||||
map: map,
|
||||
title: item.msg,
|
||||
icon: iconURL,
|
||||
visible: false
|
||||
});
|
||||
if (markerCollection["__others__"]) {
|
||||
markerCollection["__others__"].push(marker);
|
||||
} else {
|
||||
markerCollection["__others__"] = [marker];
|
||||
}
|
||||
|
||||
if (item.type == 'sign') {
|
||||
prepareSignMarker(marker, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function initialize() {
|
||||
var mapOptions = {zoom: config.defaultZoom,
|
||||
center: new google.maps.LatLng(0.5, 0.5),
|
||||
navigationControl: true,
|
||||
scaleControl: false,
|
||||
mapTypeControl: false,
|
||||
streetViewControl: false,
|
||||
mapTypeId: 'mcmap'
|
||||
};
|
||||
map = new google.maps.Map(document.getElementById("mcmap"), mapOptions);
|
||||
|
||||
if(config.debug) {
|
||||
map.overlayMapTypes.insertAt(0, new CoordMapType(new google.maps.Size(config.tileSize, config.tileSize)));
|
||||
|
||||
google.maps.event.addListener(map, 'click', function(event) {
|
||||
console.log("latLng; " + event.latLng.lat() + ", " + event.latLng.lng());
|
||||
|
||||
var pnt = map.getProjection().fromLatLngToPoint(event.latLng);
|
||||
console.log("point: " + pnt);
|
||||
|
||||
var pxx = pnt.x * config.tileSize * Math.pow(2, config.maxZoom);
|
||||
var pxy = pnt.y * config.tileSize * Math.pow(2, config.maxZoom);
|
||||
console.log("pixel: " + pxx + ", " + pxy);
|
||||
});
|
||||
}
|
||||
|
||||
// Now attach the coordinate map type to the map's registry
|
||||
map.mapTypes.set('mcmap', MCMapType);
|
||||
|
||||
// We can now set the map to use the 'coordinate' map type
|
||||
map.setMapTypeId('mcmap');
|
||||
|
||||
|
||||
// initialize the markers and regions
|
||||
initMarkers();
|
||||
initRegions();
|
||||
drawMapControls();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// our custom projection maps Latitude to Y, and Longitude to X as normal,
|
||||
// but it maps the range [0.0, 1.0] to [0, tileSize] in both directions
|
||||
// so it is easier to position markers, etc. based on their position
|
||||
// (find their position in the lowest-zoom image, and divide by tileSize)
|
||||
function MCMapProjection() {
|
||||
this.inverseTileSize = 1.0 / config.tileSize;
|
||||
}
|
||||
|
||||
MCMapProjection.prototype.fromLatLngToPoint = function(latLng) {
|
||||
var x = latLng.lng() * config.tileSize;
|
||||
var y = latLng.lat() * config.tileSize;
|
||||
return new google.maps.Point(x, y);
|
||||
};
|
||||
|
||||
MCMapProjection.prototype.fromPointToLatLng = function(point) {
|
||||
var lng = point.x * this.inverseTileSize;
|
||||
var lat = point.y * this.inverseTileSize;
|
||||
return new google.maps.LatLng(lat, lng);
|
||||
};
|
||||
|
||||
// helper to get map LatLng from world coordinates
|
||||
// takes arguments in X, Y, Z order
|
||||
// (arguments are *out of order*, because within the function we use
|
||||
// the axes like the rest of Minecraft Overviewer -- with the Z and Y
|
||||
// flipped from normal minecraft usage.)
|
||||
function fromWorldToLatLng(x, z, y)
|
||||
{
|
||||
// the width and height of all the highest-zoom tiles combined, inverted
|
||||
var perPixel = 1.0 / (config.tileSize * Math.pow(2, config.maxZoom));
|
||||
|
||||
// This information about where the center column is may change with a different
|
||||
// drawing implementation -- check it again after any drawing overhauls!
|
||||
|
||||
// point (0, 0, 127) is at (0.5, 0.0) of tile (tiles/2 - 1, tiles/2)
|
||||
// so the Y coordinate is at 0.5, and the X is at 0.5 - ((tileSize / 2) / (tileSize * 2^maxZoom))
|
||||
// or equivalently, 0.5 - (1 / 2^(maxZoom + 1))
|
||||
var lng = 0.5 - (1.0 / Math.pow(2, config.maxZoom + 1));
|
||||
var lat = 0.5;
|
||||
|
||||
// the following metrics mimic those in ChunkRenderer.chunk_render in "chunk.py"
|
||||
|
||||
// each block on X axis adds 12px to x and subtracts 6px from y
|
||||
lng += 12 * x * perPixel;
|
||||
lat -= 6 * x * perPixel;
|
||||
|
||||
// each block on Y axis adds 12px to x and adds 6px to y
|
||||
lng += 12 * y * perPixel;
|
||||
lat += 6 * y * perPixel;
|
||||
|
||||
// each block down along Z adds 12px to y
|
||||
lat += 12 * (128 - z) * perPixel;
|
||||
|
||||
// add on 12 px to the X coordinate and 18px to the Y to center our point
|
||||
lng += 12 * perPixel;
|
||||
lat += 18 * perPixel;
|
||||
|
||||
return new google.maps.LatLng(lat, lng);
|
||||
}
|
||||
|
||||
var MCMapOptions = {
|
||||
getTileUrl: function(tile, zoom) {
|
||||
var url = config.path;
|
||||
if(tile.x < 0 || tile.x >= Math.pow(2, zoom) || tile.y < 0 || tile.y >= Math.pow(2, zoom)) {
|
||||
url += '/blank';
|
||||
} else if(zoom == 0) {
|
||||
url += '/base';
|
||||
} else {
|
||||
for(var z = zoom - 1; z >= 0; --z) {
|
||||
var x = Math.floor(tile.x / Math.pow(2, z)) % 2;
|
||||
var y = Math.floor(tile.y / Math.pow(2, z)) % 2;
|
||||
url += '/' + (x + 2 * y);
|
||||
}
|
||||
}
|
||||
url = url + '.' + config.fileExt;
|
||||
if(config.cacheMinutes > 0) {
|
||||
var d = new Date();
|
||||
url += '?c=' + Math.floor(d.getTime() / (1000 * 60 * config.cacheMinutes));
|
||||
}
|
||||
return(url);
|
||||
},
|
||||
tileSize: new google.maps.Size(config.tileSize, config.tileSize),
|
||||
maxZoom: config.maxZoom,
|
||||
minZoom: 0,
|
||||
isPng: !(config.fileExt.match(/^png$/i) == null)
|
||||
};
|
||||
|
||||
var MCMapType = new google.maps.ImageMapType(MCMapOptions);
|
||||
MCMapType.name = "MC Map";
|
||||
MCMapType.alt = "Minecraft Map";
|
||||
MCMapType.projection = new MCMapProjection();
|
||||
|
||||
function CoordMapType() {
|
||||
}
|
||||
|
||||
function CoordMapType(tileSize) {
|
||||
this.tileSize = tileSize;
|
||||
}
|
||||
|
||||
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
|
||||
var div = ownerDocument.createElement('DIV');
|
||||
div.innerHTML = "(" + coord.x + ", " + coord.y + ", " + zoom + ")";
|
||||
div.innerHTML += "<br />";
|
||||
div.innerHTML += MCMapOptions.getTileUrl(coord, zoom);
|
||||
div.style.width = this.tileSize.width + 'px';
|
||||
div.style.height = this.tileSize.height + 'px';
|
||||
div.style.fontSize = '10';
|
||||
div.style.borderStyle = 'solid';
|
||||
div.style.borderWidth = '1px';
|
||||
div.style.borderColor = '#AAAAAA';
|
||||
return div;
|
||||
};
|
||||
18
web_assets/index.html
Normal file
18
web_assets/index.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
|
||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
||||
<script type="text/javascript" src="config.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="http://maps.google.com/maps/api/js?sensor=false">
|
||||
</script>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="functions.js"></script>
|
||||
<script type="text/javascript" src="markers.js"></script>
|
||||
<script type="text/javascript" src="regions.js"></script>
|
||||
</head>
|
||||
<body onload="initialize()">
|
||||
<div id="mcmap" style="width:100%; height:100%"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -16,3 +16,27 @@ body { height: 100%; margin: 0px; padding: 0px ; background-color: #000; }
|
||||
text-align: center;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
#signControl {
|
||||
padding: 5px;
|
||||
height: 15px;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
#signControl > div#top {
|
||||
background-color: #fff;
|
||||
border: 1px solid #000;
|
||||
text-align: center;
|
||||
width: 70px;
|
||||
font-size: 12px;
|
||||
width: 70px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#signControl > div#dropDown {
|
||||
border: 1px solid #000;
|
||||
font-size: 12px;
|
||||
background-color: #fff;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user