/* Copyright (c) 2006-2007 David Sheldon and Nick Burch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* File: mapTiles.js */ var size; // Size of array grid in each dimension var data; // 2 dimensional array to hold the grid data var sizeGridX = 6; // Size of visible grid (table) in each dimension var sizeGridY = 4; // Size of visible grid (table) in each dimension var minY = -86; // Minimum Y at scale 1 var tileWidth = 125; var tileHeight = 125; var markerXOffset = 4; var markerYOffset = 11; var offsetGridX = 450; var offsetGridY = 207; var zoomLevel = 1; var grid = 'osgb'; // One of osgb or osie, for now anyway var version = 'latest'; // Either "latest" or a decade eg "1920s" var needCalibration = true; var prefixes = new Array(1); var root1 = "http://ustile.npemap.org.uk/"; var root2 = "http://tile.npemap.org.uk/"; var root = "http://tile.npemap.org.uk/"; prefixes[1] = "scaled1/"; prefixes[2] = "scaled3/"; prefixes[3] = "scaled6/"; var jumpOut = new Array(1); jumpOut[1] = 3; jumpOut[2] = 2; var jumpIn = new Array(1); jumpIn[2] = 3; jumpIn[3] = 2; var zooms = new Array(1); zooms[1] = 1; zooms[2] = 3; zooms[3] = 6; var sources = new Array(1); sources[0] = 'this site'; sources[1] = 'freethepostcode.org'; sources[2] = 'npemap'; sources[3] = 'dracos postboxes'; var screenWidth = 0; var screenHeight = 0; var bottomLeft = new Array(); var doneInit = false; var markerElement; var postcodeFormElement; var mainPageElement; // Postcode specific helper functions function box1Keypress(e) { var event = YAHOO.util.Event.getEvent(e); var key = String.fromCharCode(YAHOO.util.Event.getCharCode(event)); if (key == ' ') { $('postcode2').focus(); return false; } else if (key >= '0' && key <= '9' && this.value.length == 3) { this.value = this.value + key; $('postcode2').focus(); YAHOO.util.Event.preventDefault(event); } } YAHOO.util.Event.addListener('postcode1', 'keypress', box1Keypress ); function showPostcodeWindow(easting, northing, x, y) { hideMarkerWindow(); if(postcodeFormElement == null) { // Decade based view lacks a postcode submit form return; } var easting = trimSixDigits(Math.round(easting)); var northing = trimSixDigits(Math.round(northing)); markerElement.style.visibility = 'visible'; YAHOO.util.Dom.setXY(markerElement, [(x-markerXOffset), (y-markerYOffset)]); postcodeFormElement.style.display = 'block'; YAHOO.util.Dom.setXY(postcodeFormElement, [Math.max(0, (x-50)), (y-180) < 0 ? (y+10):(y-180)]); // Compute lat+long var en = new OSRef(easting,northing); var latlong = en.toLatLng(); var lat = Math.round(latlong.lat*10000) / 10000; var lng = Math.round(latlong.lng*10000) / 10000; $('location').innerHTML = easting + ', ' + northing + " (" + lat + ", " + lng + ")"; $('easting').value = easting; $('northing').value = northing; $('returnX').value = offsetGridX; $('returnY').value = offsetGridY; $('grid').value = grid; $('grid2').value = grid; $('postcode1').value = ""; $('postcode2').value = ""; $('postcode1').focus(); } YAHOO.util.Event.addListener('postcode_submit', 'submit', submitPostcodeAjax); function submitPostcodeAjax(e) { var el = $('postcode_submit'); var data = Form.serialize(el); Element.show('status'); $('status').innerHTML = "
Submitting postcode "+ $F('postcode1') + " " + $F('postcode2') + "...
"; if (typeof urchinTracker == 'function') urchinTracker('/tiles/submitPostcode'); new Ajax.Request(el.getAttribute("action"), { method:"post", postBody:data, onComplete: function(o) {drawExisting(); updateStatus(o); } }); closePostcodeWindow(); YAHOO.util.Event.preventDefault(e); } var updateStatus = function(o) { $('status').innerHTML = o.responseText; } function closePostcodeWindow() { if(postcodeFormElement != null) { postcodeFormElement.style.display = 'none'; markerElement.style.visibility = 'hidden'; } } function showMarkerWindow(x,y, postcode, easting, northing, source, id) { closePostcodeWindow(); // Compute lat+long var en = new OSRef(easting,northing); var latlong = en.toLatLng(); var lat = Math.round(latlong.lat*10000) / 10000; var lng = Math.round(latlong.lng*10000) / 10000; // Display $('location_detail').innerHTML = easting + ", "+northing; $('latlong_detail').innerHTML = lat + ", " + lng; $('postcode_detail').innerHTML = postcode; $('grid').value = grid; $('source_detail').innerHTML = sources[source]; $('postcode_detail_window').style.display = 'block'; YAHOO.util.Dom.setXY('postcode_detail_window', [Math.max(0, (x-50)), (y-100) < 0 ? (y+10):(y-100)]); } function hideMarkerWindow() { var pdw = $('postcode_detail_window'); if(pdw != null ) { pdw.style.display = 'none'; } } // MAP METHODS -------------------------------------------- function mapClick(e) { e = YAHOO.util.Event.getEvent(e); var img = YAHOO.util.Event.getTarget(e); var x = YAHOO.util.Event.getPageX(e); var y = YAHOO.util.Event.getPageY(e); var imgPos = YAHOO.util.Dom.getXY(img); var tileX = x - imgPos[0]; var tileY = y - imgPos[1]; // Tiles are eee/nnn.jpg var tile = img.src.substring( img.src.lastIndexOf("/") - 3 ); var baseEasting = tile.substring(0, tile.indexOf("/"))-0; var baseNorthing = tile.substring(tile.indexOf("/") + 1, tile.indexOf("."))-0; var tileXratio = tileX/img.offsetWidth; var tileYratio = 1 -(tileY/img.offsetHeight); if (zoomLevel != 1) { // Zoom in. gotoLocation(Math.round((baseEasting -0 + tileXratio) * zooms[zoomLevel]), Math.round((baseNorthing -0 + tileYratio) * zooms[zoomLevel]), zoomLevel - 1); } } YAHOO.util.Event.addListener('map', 'click', mapClick); function zoomOut() { if(zoomLevel == (prefixes.length-1)) { location.href="allmaps.html"; return; } tidyUp(); gotoLocation(offsetGridX * zooms[zoomLevel], offsetGridY * zooms[zoomLevel], zoomLevel + 1); } function tidyUp() { removeMarkers(); } function zoomIn() { if(zoomLevel == 1) { return; } gotoLocation(offsetGridX * zooms[zoomLevel], offsetGridY * zooms[zoomLevel], zoomLevel - 1); } function fixZoomButton() { if(zoomLevel == 1) { Element.hide('zoomin_enabled'); Element.show('zoomin_disabled'); Element.show('showHideMarkers'); } else { Element.show('zoomin_enabled'); Element.hide('zoomin_disabled'); Element.hide('showHideMarkers'); } } function doResize() { var newWidth = YAHOO.util.Dom.getViewportWidth(); var newHeight = YAHOO.util.Dom.getViewportHeight(); if (screenHeight != newHeight || screenWidth != newWidth) { screenWidth = YAHOO.util.Dom.getViewportWidth(); screenHeight = YAHOO.util.Dom.getViewportHeight(); drawTable(); refreshGrid(); } } function drawTable() { sizeGridX = Math.floor(((screenWidth -210) / tileWidth)); sizeGridY = Math.floor(((screenHeight -130) / tileHeight)); var map = $('map'); map.innerHTML = ''; for(var y=sizeGridY; y>=1; y--) { for(var x=1; x<=sizeGridX; x++) { map.appendChild(createIMG(tileWidth, tileHeight, 'element'+x+'.'+y)); } map.appendChild(document.createElement('br')); } $('map').style.width = (sizeGridX * tileWidth) + "px" ; } function createIMG(width, height, id) { var img = document.createElement('img'); img.width = width; img.height = height; img.id = id; return img; } function setVersion(tileVersion) { if(tileVersion != null) { version = tileVersion; } } function initializePage(skipMarkers, tileVersion) { markerElement = $('marker'); postcodeFormElement = $('postcode_form'); mainPageElement = $('main_page'); doneInit = true; if(tileVersion != null) { version = tileVersion; } if(skipMarkers != null && skipMarkers) { } else { updateShowMarkers(); } parseQueryString(); fixZoomButton(); doResize(); } function reload_page() { parseQueryString(); fixZoomButton(); refreshGrid(); } function parseQueryString() { var hash = location.href.lastIndexOf('#'); var query = location.href.lastIndexOf("?") var params = ''; if (hash != -1) { params = location.href.substring(hash+1); } else if (query != -1) { params = location.href.substring(query+1); } if (params.length > 0) { urlterms=params.split(",") offsetGridX = urlterms[0]-0 ; offsetGridY = urlterms[1]-0 ; if(urlterms.length > 2) { zoomLevel = urlterms[2]-0 ; } grid = 'osgb'; if(urlterms.length > 3) { if(urlterms[3] == 'ie') { grid = 'osie'; } } } } function gotoLocation(easting, northing, zoom) { offsetGridX = Math.round(easting / zooms[zoom]); offsetGridY = Math.round(northing/ zooms[zoom]); zoomLevel = zoom; fixZoomButton(); refreshGrid(); } // Need to use substring for IE // Pads to 3 digits with zeros, or - and 2 digits function trimNumber(string) { // If we have a 3+ digit number, no need to do any padding if(parseInt(string) >= 100) { return string; } // Or a 2+ digit negative number, no need to do any padding if(parseInt(string) <= -10) { return string; } // Special case for 1 digit negative numbers if(parseInt(string) <= 0) { var num = parseInt(string); return '-0' + (0-num); } // Pad it so that it'll always have leading 0s, and be at least 3 long str = '000' + string // Grab the right most 3 digits, which will have any required padding return str.substring(str.length -3) } function trimSixDigits(string) { // If we have a 6+ digit number, no need to do any padding if(parseInt(string) >= 100000) { return string; } // Or a 5+ digit negative number, no need to do any padding if(parseInt(string) <= -10000) { return string; } // Is it negative? var num = parseInt(string) var isNegative = (num < 0); if(isNegative) { num = 0 - num; } // Pad it so that it'll always have leading 0s, and be at least 6 long str = '000000' + num; // Grab the right most 6 digits, which will have any required padding str = str.substring(str.length -6) // Add back in - at start if needed if(isNegative) { str = '-' + str.substring(1); } return str; } function refreshGrid() { if (!doneInit) { // Page is still loading, wait some more return; } closePostcodeWindow(); hideMarkerWindow(); for(var x=1; x<=sizeGridX; x++) { for(var y=1; y<=sizeGridY; y++) { tileX = x+offsetGridX-Math.round(sizeGridX/2); tileY = y+offsetGridY-Math.round(sizeGridY/2); $('element' + x + '.' + y).src = tileURL(tileX, tileY); } } minEasting = (offsetGridX-Math.round(sizeGridX/2))+1; minNorthing= (offsetGridY-Math.round(sizeGridY/2))+1; maxEasting = minEasting + sizeGridX; maxNorthing= minNorthing + sizeGridY; if (zoomLevel == 1) { drawExisting(); } updatePermalink(); updateSheets(minEasting,minNorthing,maxEasting,maxNorthing); } function tileURL(tileX, tileY) { //var root = (tileX % 2) == 0 ? root1 : root2; return root + grid + '/' + version + '/' + prefixes[zoomLevel] + trimNumber(tileX)+'/'+ trimNumber(tileY) + '.jpg'; } function drawExisting() { if (shouldWeShowMarkers()) { var url = "/cgi/get-postcodes.fcgi"; var params = "mineasting=" + minEasting + "000&maxeasting=" + maxEasting + "000&minnorthing=" + minNorthing + "000&maxnorthing=" + maxNorthing+"000" + "&grid=" + grid; removeMarkers(); $('spinner').innerHTML = "Loading....
"; needCalibration = true; var myAjax = new Ajax.Request(url, { method: 'get', parameters: params, onComplete: successHandler, onFailure: failHander }); } } var successHandler = function(o){ eval(o.responseText); } var failHander = function(o) { // Don't do anything $('spinner').innerHTML = 'Problem showing existing data.
'; } function findMarkerOffsets() { newMarker = document.createElement('div'); newMarker.style.position = 'absolute'; mainPageElement.appendChild(newMarker); topLeft = YAHOO.util.Dom.getXY('element1.' + sizeGridY); var bottom = topLeft[1] + (tileHeight*sizeGridY); YAHOO.util.Dom.setXY(newMarker, [topLeft[0] - markerXOffset, bottom - markerYOffset]); markerLeft = parseInt(newMarker.style.left); markerTop= parseInt(newMarker.style.top); mainPageElement.removeChild(newMarker); needCalibration = false; } function completeMarkers() { $('spinner').innerHTML = " "; } var markers = new Array(); var nextMarker = 0; function removeMarkers() { var pageElement = $('main_page'); for(var i=0; i