/* * Copyright (c) 2009 Industry Canada * * @author MROZJ, PITTA * @since May 27, 2009 */ // global vars // the Google map instance var map; // The error box var error_box; // Geocoder for finding by address var geocoder; // used for Please Wait messages, a flag to indicate that an async request // is still happening; if true then when doPleaseWait is called it does show // a message, otherwise it assumes the request is complete and does nothing var outstandingRequest = false; // the last GPoint the user clicked, also for doPleaseWait. var lastPoint; // how long to wait for an async response before showing the Please Wait message var PLEASE_WAIT_DELAY = 500; // initial zoom level var INITIAL_ZOOM = 3; // Zoom after text-based search. var POST_TEXT_SEARCH_ZOOM = 13; // Zoom after map click. var POST_CLICK_ZOOM = 5; // Draw hexagons flag. var DRAW_HEXAGONS = true; // Default lat/lng offsets to use when drawing hexagons. var LAT_OFFSET = 0.024; var LNG_OFFSET = 0.04018666666667059; // Hexagon display details. var HEX_BORDER_THICKNESS = 2; var HEX_BORDER_OPACITY = 0.5; //var HEX_BORDER_COLOR = "#f33f00"; var HEX_BORDER_COLOR = "#000000"; var HEX_FILL_OPACITY = 0; var HEX_FILL_COLOR = "#ff0000"; // Division display details. var LINE_THICKNESS = 1; var LINE_OPACITY = 0.5; var LINE_COLOR = HEX_BORDER_COLOR; // InfoWindow options. var INFO_WINDOW_OPTIONS = {maxWidth:325}; // Maximum # of providers listed in call-out. var MAX_LISTED_PROVIDERS = 4; /** * Handler for click events. */ function clickHandler(overlay, point, overlayLatLng) { if (overlay) { // If a non-clickable overlay (hexagons), // pass the overlayLatLng GLatLng point. //return overlayLatLng; return; } // center on the selected point map.setCenter(point); if (map.getZoom() < POST_CLICK_ZOOM) { map.setZoom(POST_CLICK_ZOOM); } // the real handler doStep1(point); } /** * Show the popup when a location is selected. */ function doStep1(point) { // record for Please Wait message lastPoint = point; // this is used for the Please Wait message outstandingRequest = true; setTimeout("doPleaseWait();", PLEASE_WAIT_DELAY); // invoke the second step doStep2(point); } /** * Please Wait * * Show a Please Wait type message if the query isn't super-fast. */ function doPleaseWait() { // only show if the AJAX request hasn't completed yet if(outstandingRequest) { // feedback for slow connections or high server load map.openInfoWindow(lastPoint, "
Finding your service area...
", INFO_WINDOW_OPTIONS); } // else: request completed quickly } /** * Given a lat/long point, do a reverse geocode lookup, and then perform the final query. */ function doStep2(point) { var province = ""; // do reverse geocoder search geocoder.getLocations(point, function(addresses) { if(addresses.Status.code == 200) { // some places just don't have reverse geocoding data, ie, lakes, unpopulated areas; // in this case we just don't filter by province, since there's still SITT data // related to these areas typically. This filter only affects border areas. var address = addresses.Placemark[0]; var province = ""; if( address.AddressDetails && address.AddressDetails.Country && address.AddressDetails.Country.AdministrativeArea && address.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName ) { province = address.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName; } else if (address && address.address) { var addressParts = address.address.split(","); if (addressParts && addressParts.length >= 2) { var prov = addressParts[addressParts.length - 2]; if (prov.indexOf("O") == 1) { province = "ON"; } else if (prov.indexOf("Q") == 1) { province = "QC"; } else if (prov.indexOf("M") == 1) { province = "MB"; } else if (prov.indexOf("A") == 1) { province = "AB"; } else if (prov.indexOf("B") == 1) { province = "BC"; } else if (prov.indexOf("P") == 1) { province = "PE"; } else if (prov.indexOf("S") == 1) { province = "SK"; } else if (prov.indexOf("Y") == 1) { province = "YK"; } else if (prov.indexOf("Newf") == 1) { province = "NL"; } else if (prov.indexOf("Nov") == 1) { province = "NS"; } else if (prov.indexOf("Nor") == 1) { province = "NT"; } else if (prov.indexOf("Nu") == 1) { province = "NU"; } } } else { debug("Reverse geocoding found no province."); } } // this is only handled herein because the proceeding AJAX call into Google // must complete first. // the backend query URL var url = determineQueryUrl(point, province); debug(url); // execute the final AJAX call $.getJSON(url, function(data) { outstandingRequest = false; hexSearchCallback(data, point); }); }); } /** * Create the points of a hexagonal polygon. * @param latitude * @param longitude * @return GLatLng[] */ function createHexPolygonPoints(centerPoint, latOffset, lngOffset) { var lngOffsetHalf = lngOffset / 2; var p1 = new GLatLng(centerPoint.lat(), centerPoint.lng() + lngOffset); var p2 = new GLatLng(centerPoint.lat() + latOffset, centerPoint.lng() + lngOffsetHalf); var p3 = new GLatLng(centerPoint.lat() + latOffset, centerPoint.lng() - lngOffsetHalf); var p4 = new GLatLng(centerPoint.lat(), centerPoint.lng() - lngOffset); var p5 = new GLatLng(centerPoint.lat() - latOffset, centerPoint.lng() - lngOffsetHalf); var p6 = new GLatLng(centerPoint.lat() - latOffset, centerPoint.lng() + lngOffsetHalf); return [p1, p2, p3, p4, p5, p6, p1]; } /** * Divide up a hexagon into it's six parts. * @param polyPoints - GLatLng[] - Points of hexagon to be divided up. * @param centerPoint - Center point of hexagon. */ function addDivisions(polyPoints, centerPoint) { for (i=0; i < polyPoints.length; i++) { map.addOverlay(new GPolyline( [centerPoint, polyPoints[i]], LINE_COLOR, LINE_THICKNESS, LINE_OPACITY, {clickable:false})); } } /** * Create a hexagonal polygon based on the points provided. * @param polyPoints - GLatLng[] - Array of points that make the hexagon. */ function createHexagonPoly(polyPoints) { return new GPolygon( polyPoints, HEX_BORDER_COLOR, HEX_BORDER_THICKNESS, HEX_BORDER_OPACITY, HEX_FILL_COLOR, HEX_FILL_OPACITY, {clickable:false}); } /** * Callback function for the HexareaSearch async service. */ function hexSearchCallback(data, point) { //debug("JSON.location: " + data.location); // first remove any existing map.clearOverlays(); // add one for this instance var marker = new GMarker(point); map.addOverlay(marker); // what goes into the info window var bubbleHtml; var providerListHtml; if (data.results == 0) { bubbleHtml = "No service information was found for your area.
"; providerListHtml = bubbleHtml; } else { var locationStr = data.location; // If French, replace "W" with "O" for "West" initial. if ('eng' == 'fra') { locationStr = locationStr.replace("°W","°O"); } var hrefOpen = ""; bubbleHtml = "" + hrefOpen + locationStr + "
" + "" + hrefOpen + "View Summary Information / Submit Feedback
"; providerListHtml = bubbleHtml; if(data.providers && data.providers.length > 0) { // providers found //bubbleHtml += ""; providerListHtml += "Broadband Providers
No providers have been located. Please " + hrefOpen + "submit feedback to add a provider.
"; providerListHtml = bubbleHtml; } $("#provider_list").html(providerListHtml); } // show it map.openInfoWindow(point, bubbleHtml, INFO_WINDOW_OPTIONS); if (DRAW_HEXAGONS) { // Center point of central hexagon. var mainHexCenter = new GLatLng(data.hexLat, data.hexLon); var neighbourCenters = new Array(); // Determine the lat/lng offset for drawing hexagons. if (typeof(data.neighbours) != "undefined" && data.neighbours.length > 0) { // Create center points for neighbours. for (i=0; i < data.neighbours.length; i++) { neighbourCenters[i] = new GLatLng(data.neighbours[i].latitude, data.neighbours[i].longitude); } } var latOffset = calculateLatitudeOffset(mainHexCenter, neighbourCenters); debug("Lat/Lng offsets: " + latOffset + "/" + LNG_OFFSET); // Create the central hexagon and add divisions. var polyPoints = createHexPolygonPoints(mainHexCenter, latOffset, LNG_OFFSET); map.addOverlay(createHexagonPoly(polyPoints), {clickable:false}); addDivisions(polyPoints, mainHexCenter); // Draw neighbour hexagons. for (i=0; i < neighbourCenters.length; i++) { map.addOverlay(createHexagonPoly(createHexPolygonPoints(neighbourCenters[i], latOffset, LNG_OFFSET)), {clickable:false}); } } } /** * Determine the query URL for finding a community based on lat/long. */ function determineQueryUrl(point, provinceCode) { var str = point.toUrlValue(6); var arr = str.split(","); var lat = arr[0]; var lng = arr[1]; var baseUrl = window.location.protocol + "//" + window.location.host; // server-relative URL prefix var urlPrefix = baseUrl + "/app/sitt/bbmap/hx.json;jsessionid=0001y3fEklOyEutIpb9_1rhSIJs:1459UUUUEF?"; // full generated URL var url = urlPrefix + "la=" + lat + "&lo=" + lng; if(provinceCode) { url = url + "&pc="+ provinceCode; } return url; } /** * Calculate the distance from a center point to the top/bottom of a hexagon in terms of latitude offset. * @param centerPoint - GLatLng - Center point of central hexagon. * @param neighbours - GLatLng[] - Array of center points of neighbour hexagons. * @return double - Latitude offset. */ function calculateLatitudeOffset(centerPoint, neighbours) { var offsetTotal = 0; if (neighbours.length > 0) { for (i = 0; i < neighbours.length; i++) { // Isolate longitude. var lngOnly = new GLatLng(centerPoint.lat(), neighbours[i].lng()); // Isolate latitude. var latOnly = new GLatLng(neighbours[i].lat(), centerPoint.lng()); // Calculation for a diagonal cell (2/3 odds this is the case). var offsetContribution = Math.abs(centerPoint.lat() - neighbours[i].lat()); // If not a diagonal cell, divide result by 2. if (lngOnly.distanceFrom(centerPoint) < 500) { // This is directly above/below. offsetContribution = offsetContribution / 2; } // Add offset to running total. offsetTotal += offsetContribution; } // Return the average offset. return offsetTotal / neighbours.length; } // No other hexagons to use as reference, // so return default latitude offset. return LAT_OFFSET; } /** * Calculate the distance from a center point to the left/right of a hexagon in terms of longitude offset. * @param centerPoint - GLatLng - Center point of central hexagon. * @param neighbours - GLatLng[] - Array of center points of neighbour hexagons. * @return double - Latitude offset. */ function calculateLongitudeOffset(centerPoint, neighbours) { return LNG_OFFSET; } function debug(message) { if(window.location.href.lastIndexOf("#debug") != -1) { GLog.write(message); } } // Let jQuery bind functions to DOM objects. $(document).ready(function() { // Initialize map. if (GBrowserIsCompatible()) { // initialize the map, setting a reasonable default location //var startingPoint = new GLatLng(45.41877168115324, -75.7009184360504); var startingPoint = new GLatLng(59.521, -96.592); map = new GMap2(document.getElementById("map_canvas")); map.setMapType(G_NORMAL_MAP); map.setCenter(startingPoint, INITIAL_ZOOM); map.setUIToDefault(); GEvent.addListener(map, "click", clickHandler); // initialize the geocoder for looking up addresses geocoder = new GClientGeocoder(); } // Add a submit handler to the form. $("#gmapForm").submit(function(event){ // Prevent the form from actually submitting. event.preventDefault(); // Grab the address from the text box. var address = $("#gaddress").val() + " Canada"; debug(address); if(address != "") { geocoder.getLatLng( address, function(point) { if (!point) { debug("No Address"); error_box = document.getElementById("error_box"); error_box.style.display = "block"; } else { debug("Has point"); error_box = document.getElementById("error_box"); error_box.style.display= "none"; map.setCenter(point, POST_TEXT_SEARCH_ZOOM); doStep1(point); } } ); } }); $(window).unload( function () { GUnload(); } ); });