/* * Copyright (C) 2011 Brian Ferris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var OBA = window.OBA || {}; /******************************************************************************* * Common Methods ******************************************************************************/ var obaCommonFactory = function() { var that = {}; that.buildUrlQueryString = function(params) { var queryString = ''; var seenFirst = false; for( var key in params ) { var values = params[key]; if( ! (values instanceof Array)) values = [values]; jQuery.each(values,function() { if( seenFirst ) { queryString += '&'; } else { queryString += '?'; seenFirst = true; } queryString += encodeURIComponent(key) + '=' + encodeURIComponent(this); }); } return queryString; }; return that; }; OBA.Common = obaCommonFactory(); /* * Copyright (C) 2011 Brian Ferris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var OBA = window.OBA || {}; /******************************************************************************* * API Methods ******************************************************************************/ var obaApiFactory = function() { var that = {}; /*************************************************************************** * API URL Methods **************************************************************************/ var createUrl = function(url) { return OBA.Config.apiBaseUrl + "/api" + url; } var createParams = function(otherParams) { var params = { key : OBA.Config.obaApiKey, version : 2 }; if (otherParams) { // Come on now 1 for( var name in otherParams) { params[name] = otherParams[name]; } } return params; }; /*************************************************************************** * API Callback Handler Methods **************************************************************************/ var createHandler = function(callback, errorCallback) { if (!errorCallback) { var errorCallback = function(textStatus) { }; } return function(json) { if (json && json.code == 200) { callback(json.data); return; } errorCallback(textStatus); }; }; var createEntryHandler = function(callback, errorCallback, postProcess) { var entryHandler = function(json) { // Eventually, we will do smart handling of references here var references = processReferences(json.references); var entry = json.entry; if( postProcess ) postProcess(entry, references); callback(entry); }; return createHandler(entryHandler, errorCallback); }; var createListHandler = function(callback, errorCallback, postProcess) { var listHandler = function(json) { // Eventually, we will do smart handling of references here var references = processReferences(json.references); var list = json.list; if( postProcess ) { for ( var i = 0; i < list.length; i++) { postProcess(list[i], references); } } callback(json); }; return createHandler(listHandler, errorCallback); }; /*************************************************************************** * JSON Post-Processing Methods **************************************************************************/ var processReferencesById = function(values) { var valuesById = {}; if (values) { for ( var i = 0; i < values.length; i++) { var value = values[i]; valuesById[value.id] = value; } } return valuesById; }; var processReferences = function(references) { references.agenciesById = processReferencesById(references.agencies); references.routesById = processReferencesById(references.routes); references.stopsById = processReferencesById(references.stops); references.tripsById = processReferencesById(references.trips); references.situationsById = processReferencesById(references.situations); jQuery.each(references.routes || [], function(){ processRoute(this, references); }); jQuery.each(references.stops || [], function(){ processStop(this, references); }); jQuery.each(references.trips || [], function(){ processTrip(this, references); }); return references; }; var processAgencyWithCoverage = function(awc, references) { awc.agency = references.agenciesById[awc.agencyId]; }; var processArrivalAndDepartureForStop = function(entry, references) { }; var processItineraries = function(entry, references) { var itineraries = entry.itineraries || []; jQuery.each(itineraries,function() { var legs = this.legs || []; jQuery.each(legs, function() { var transitLeg = this.transitLeg; if( ! transitLeg ) return; transitLeg.fromStop = references.stopsById[transitLeg.fromStopId]; transitLeg.toStop = references.stopsById[transitLeg.toStopId]; transitLeg.trip = references.tripsById[transitLeg.tripId]; }); }); } var processItinerary = function(entry, references) { } var processRoute = function(route, references ) { var agency = references.agenciesById[route.agencyId]; if( agency ) route.agency = agency; }; that.processSituation = function(situation, references) { var affects = situation.affects || {}; var affectedAgencies = affects.agencies || []; var affectedStops = affects.stops || []; var affectedVehicleJourneys = affects.vehicleJourneys || []; jQuery.each(affectedAgencies, function() { var agency = references.agenciesById[this.agencyId]; if( agency != undefined ) this.agency = agency; }); jQuery.each(affectedStops, function() { var stop = references.stopsById[this.stopId]; if( stop != undefined ) this.stop = stop; }); jQuery.each(affectedVehicleJourneys, function() { var route = references.routesById[this.lineId]; if( route != undefined) this.route = route; var calls = this.calls || []; jQuery.each(calls, function() { var stop = references.stopsById[this.stopId]; if( stop != undefined ) this.stop = stop; }); }); } var processStop = function(stop, references) { var routes = new Array(); stop.routes = routes; jQuery.each(stop.routeIds,function() { var route = references.routesById[this]; if( route ) routes.push(route); }); }; var processStopIds = function(stopIds, stops, references) { jQuery.each(stopIds || [], function() { var stop = references.stopsById[this]; if( stop ) stops.push(stop); }); }; var processStopsForRoute = function(stopsForRoute, references) { var route = references.routesById[stopsForRoute.routeId]; if( route ) stopsForRoute.route = route; stopsForRoute.stops = []; processStopIds( stopsForRoute.stopIds, stopsForRoute.stops, references); jQuery.each(stopsForRoute.stopGroupings || [], function() { var stopGrouping = this; jQuery.each(stopGrouping.stopGroups, function() { var stopGroup = this; stopGroup.stops = []; processStopIds( stopGroup.stopIds, stopGroup.stops, references); }); }); }; var processStreetGraphForRegion = function(entry, references) { var verticesById = {}; var vertices = entry.vertices || []; jQuery.each(vertices,function() { verticesById[this.id] = this; }); var edges = entry.edges || []; jQuery.each(edges,function() { var from = verticesById[this.fromId]; if( from ) this.from = from; var to = verticesById[this.toId]; if( to ) this.to = to; }); }; var processTrip = function(trip, references) { var route = references.routesById[trip.routeId]; if( route ) trip.route = route; }; var processTripDetails = function(tripDetails, references) { var trip = references.tripsById[tripDetails.tripId]; if( trip ) tripDetails.trip = trip; if( tripDetails.schedule ) processTripSchedule( tripDetails.schedule, references); if( tripDetails.status ) processTripStatus( tripDetails.status ); }; var processTripSchedule = function(schedule, references) { var stopTimes = schedule.stopTimes; if( stopTimes ) { jQuery.each(stopTimes, function() { processTripStopTime(this,references); }); } var prevTrip = references.tripsById[schedule.previousTripId]; if( prevTrip ) schedule.previousTrip = prevTrip; var nextTrip = references.tripsById[schedule.nextTripId]; if( nextTrip ) schedule.nextTrip = nextTrip; }; var processTripStopTime = function(stopTime, references) { var stop = references.stopsById[stopTime.stopId]; if( stop ) stopTime.stop = stop; }; var processTripStatus = function(tripStatus, references) { }; var processHistoricalOccupancy = function(occupancy, references) { }; /*************************************************************************** * Public API Methods **************************************************************************/ that.createEntryHandler = createEntryHandler; that.createListHandler = createListHandler; that.agenciesWithCoverage = function(callback, errorCallback) { var url = createUrl('/where/agencies-with-coverage.json'); var params = createParams(); var handler = createListHandler(callback, errorCallback, processAgencyWithCoverage); jQuery.getJSON(url, params, handler); }; that.arrivalAndDepartureForStop = function(userParams, callback, errorCallback) { var url = createUrl('/where/arrival-and-departure-for-stop/' + userParams.stopId + '.json'); var params = createParams(userParams); var handler = createEntryHandler(callback, errorCallback, processArrivalAndDepartureForStop); jQuery.getJSON(url, params, handler); }; that.route = function(routeId, callback, errorCallback) { var url = createUrl('/where/route/' + routeId + '.json'); var params = createParams(); var handler = createEntryHandler(callback, errorCallback, processRoute); jQuery.getJSON(url, params, handler); }; that.routesForLocation = function(params, callback, errorCallback) { var url = createUrl('/where/routes-for-location.json'); params = createParams(params); var handler = createListHandler(callback, errorCallback, processRoute); jQuery.getJSON(url, params, handler); }; that.shape = function(shapeId, callback, errorCallback) { var url = createUrl('/where/shape/' + shapeId + '.json'); var params = createParams(); var handler = createEntryHandler(callback, errorCallback); jQuery.getJSON(url, params, handler); }; that.stop = function(stopId, callback, errorCallback) { var url = createUrl('/where/stop/' + stopId + '.json'); var params = createParams(); var handler = createEntryHandler(callback, errorCallback, processStop); jQuery.getJSON(url, params, handler); }; that.stopsForLocation = function(params, callback, errorCallback) { var url = createUrl('/where/stops-for-location.json'); var urlParams = createParams(params); var handler = createListHandler(callback, errorCallback, processStop); jQuery.getJSON(url, urlParams, handler); }; that.stopsForRoute = function(routeId, callback, errorCallback) { var url = createUrl('/where/stops-for-route/' + routeId + '.json'); var params = createParams(); var handler = createEntryHandler(callback, errorCallback, processStopsForRoute); jQuery.getJSON(url, params, handler); }; that.streetGraphForRegion = function(bounds, callback, errorCallback) { if( bounds.isEmpty() ) return; var ne = bounds.getNorthEast(); var sw = bounds.getSouthWest(); var params = {}; params.latFrom = sw.lat(); params.lonFrom = sw.lng(); params.latTo = ne.lat(); params.lonTo = ne.lng(); params = createParams(params); var url = createUrl('/where/street-graph-for-region.json'); var handler = createEntryHandler(callback, errorCallback, processStreetGraphForRegion); jQuery.getJSON(url, params, handler); }; that.tripDetails = function(params, callback, errorCallback) { var url = createUrl('/where/trip-details/' + params.tripId + '.json'); var params = createParams(params); var handler = createEntryHandler(callback, errorCallback, processTripDetails); jQuery.getJSON(url, params, handler); }; that.historicalOccupancyForStop = function(params, callback, errorCallback) { var url = createUrl('/where/historical-occupancy-by-stop/' + params.stopId + '.json'); var params = createParams(params); var handler = createEntryHandler(callback, errorCallback, processHistoricalOccupancy); jQuery.getJSON(url, params, handler); }; return that; }; OBA.Api = obaApiFactory(); /* * Copyright (C) 2011 Brian Ferris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var OBA = window.OBA || {}; /******************************************************************************* * L10n Methods ******************************************************************************/ OBA.L10n = {}; OBA.L10n.ChoiceFormat = function(message) { }; /* * Adapted from Date Format 1.2.3 * (c) 2007-2009 Steven Levithan * MIT license * * Includes enhancements by Scott Trenda * and Kris Kowal */ OBA.L10n.DateFormat = function(format) { var pad = function (val, len) { val = String(val); len = len || 2; while (val.length < len) val = "0" + val; return val; }; var token = /d{1,4}|m{1,4}|yy(?:yy)?|([aAHhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g; var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g; var timezoneClip = /[^-+\dA-Z]/g; var that = {}; that.format = function(date) { var utc = false; var _ = utc ? "getUTC" : "get"; var vd = date[_ + "Date"](); var vD = date[_ + "Day"](); var vM = date[_ + "Month"](); var vy = date[_ + "FullYear"](); var vH = date[_ + "Hours"](); var vm = date[_ + "Minutes"](); var vs = date[_ + "Seconds"](); var vL = date[_ + "Milliseconds"](); var vo = utc ? 0 : date.getTimezoneOffset(); var flags = {}; flags.yy = String(vy).slice(2); flags.yyyy = vy; flags.M = vM + 1; flags.MM = pad(flags.M); flags.MMM = OBA.Resources.DateLibrary['shortMonths'][vM]; flags.MMMM = OBA.Resources.DateLibrary['months'][vM]; flags.d = vd; flags.dd = pad(vd); flags.h = vH % 12 || 12; flags.hh = pad(flags.h); flags.m = vm + 1, flags.mm = pad(flags.m); flags.AA = OBA.Resources.DateLibrary['amPm'][vH < 12 ? 0 : 1]; flags.aa = flags.AA.toLowerCase(); /* flags = { d: d, dd: pad(d), ddd: dF.i18n.dayNames[D], dddd: dF.i18n.dayNames[D + 7], m: m + 1, mm: pad(m + 1), mmm: dF.i18n.monthNames[m], mmmm: dF.i18n.monthNames[m + 12], yy: String(y).slice(2), yyyy: y, H: H, HH: pad(H), K: H % 12, KK: pad(H % 12), M: M, MM: pad(M), s: s, ss: pad(s), l: pad(L, 3), L: pad(L > 99 ? Math.round(L / 10) : L), t: H < 12 ? "a" : "p", tt: H < 12 ? "am" : "pm", T: H < 12 ? "A" : "P", TT: H < 12 ? "AM" : "PM", Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] }; */ return format.replace(token, function ($0) { return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); }); }; return that; }; OBA.L10n.MessageFormat = function(message) { var that = {}; var parseSubFormat = function(type,args) { if( type == 'choice') { return OBA.L10n.ChoiceFormat(args); } else if( type == 'date') { return OBA.L10n.DateFormat(args); } else { return function(arg) { return arg; }; } }; var parseMessage = function(message) { var parts = new Array(); /** * What depth of the format stack are we in: * * "000 {111,222,333} 000 {111,222,333}" * * 0 - basic text * 1 - argument index * 2 - format type * 3 - format arguments */ var formatDepth = 0; /** * A stack of strings for each depth of the format message (0-3), where the latest * content for each depth is appended to the appropriate string */ var formatStack = ['','','','']; var inQuote = false; var braceDepth = 0; for (var i = 0; i < message.length; i++) { var ch = message.charAt(i); if (formatDepth == 0) { if (ch == '\'') { /** * Allow escaping a single quote with '' */ if (i + 1 < message.length && message.charAt(i+1) == '\'') { formatStack[formatDepth] += ch; i++; } else { inQuote = !inQuote; } } else if (ch == '{' && !inQuote) { if( formatStack[0].length > 0) { parts.push({'value':formatStack[0]}); formatStack[0] = ''; } formatDepth = 1; } else { formatStack[formatDepth] += ch; } } else if (inQuote) { formatStack[formatDepth] += ch; if (ch == '\'') { inQuote = false; } } else { switch (ch) { case ',': if (formatDepth < 3) formatDepth += 1; else formatStack[formatDepth] += ch; break; case '{': braceDepth++; formatStack[formatDepth] += ch; break; case '}': if (braceDepth == 0) { formatDepth = 0; var formatter = parseSubFormat(formatStack[2],formatStack[3]); var argumentIndex = parseInt(formatStack[1]); parts.push({'formatter':formatter,'argumentIndex':argumentIndex}); // Reset everything for (var j = 0; j < formatStack.length; ++j) { formatStack[j] = ''; } } else { braceDeptch--; formatStack[formatDepth] += ch; } break; case '\'': inQuote = true; // fall through, so we keep quotes in other parts default: formatStack[formatDepth] += ch; break; } } } if (braceDepth == 0 && formatDepth != 0) throw "expected closing brace in message format"; if( formatStack[0].length > 0) { parts.push({'value':formatStack[0]}); formatStack[0] = ''; } return parts; }; var parts = parseMessage(message); that.format = function() { var result = ''; for( var i=0; i < parts.length; i++) { var part = parts[i]; if( part.value ) { result += part.value; } else if( part.formatter ) { if( part.argumentIndex >= arguments.length ) { result += '{' + part.argumentIndex + '}'; } else { var arg = arguments[part.argumentIndex]; result += part.formatter(arg); } } } return result; }; return that; }; OBA.L10n.format = function() { var slice = Array.prototype.slice; var args = slice.apply(arguments); var message = args.shift(); if( !message ) return ''; var m = OBA.L10n.MessageFormat(message); return m.format.apply(m,args); }; OBA.L10n.formatDate = function() { var slice = Array.prototype.slice; var args = slice.apply(arguments); var message = args.shift(); if( !message ) return ''; var m = OBA.L10n.DateFormat(message); return m.format.apply(m,args); }; /* * Copyright (C) 2011 Brian Ferris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var OBA = window.OBA || {}; /******************************************************************************* * Presentation Methods ******************************************************************************/ OBA.Presentation = function() { var that = {}; that.nameAsString = function(name) { var result = ''; jQuery.each(name.names, function() { if( result.length > 0) result += ' '; result += this; }); return result; }; that.getNameForRoute = function(route) { var name = route.shortName; if( name == undefined || name == null || name.length == 0) name = route.longName; if( name == undefined || name == null || name.length == 0) name = route.id; return name; }; that.applyStopNameToElement = function(stop,content) { content.find(".stopName").text(stop.name); var stopCodeSpan = content.find(".stopCode"); var stopCodeText = OBA.L10n.format(stopCodeSpan.text(), stop.code); stopCodeSpan.text(stopCodeText); var stopDirectionSpan = content.find(".stopDirection"); if( stop.direction ) { var stopDirectionText = OBA.L10n.format(stopDirectionSpan.text(), stop.direction); stopDirectionSpan.text(stopDirectionText); } else { stopDirectionSpan.hide(); } }; that.createStopInfoWindow = function(stop, params) { params = params || {}; var templateClassName = params.templateClassName || 'StopInfoWindowTemplate'; var content = jQuery('.' + templateClassName).clone(); content.removeClass('StopInfoWindowTemplate'); content.addClass('StopInfoWindow'); that.applyStopNameToElement(stop,content); configureStopInfoWindowRoutes(stop, content, params); return content; }; /**** * Private Methods ****/ var configureStopInfoWindowRoutes = function(stop, content, params) { var routes = stop.routes; var routesSection = content.find('.routesSection'); var routeClickHandler = params.routeClickHandler; if( routes == undefined || routes.length == 0 || params.hideRoutes) { routesSection.hide(); return } var shortNameRoutes = []; var longNameRoutes = []; jQuery.each(routes, function() { var name = that.getNameForRoute(this); if( name.length > 3) longNameRoutes.push(this); else shortNameRoutes.push(this); }); if( shortNameRoutes.length > 0) { var shortNameRoutesPanel = jQuery('
'); shortNameRoutesPanel.addClass('routesSubSection'); shortNameRoutesPanel.appendTo(routesSection); jQuery.each(shortNameRoutes, function() { var w = jQuery(''); w.addClass('routeShortName'); w.text(that.getNameForRoute(this)); w.appendTo(shortNameRoutesPanel); if( routeClickHandler ) { w.click(function() { routeClickHandler(route,stop); }); } }); } if( longNameRoutes.length > 0) { var longNameRoutesPanel = jQuery('
'); longNameRoutesPanel.addClass('routesSubSection'); longNameRoutesPanel.appendTo(routesSection); jQuery.each(longNameRoutes, function() { var name = that.getNameForRoute(this); var w = jQuery('
'); w.addClass('routeLongName'); if( name.length > 10 ) w.addClass('routeReallyLongName'); w.text(name); w.appendTo(longNameRoutesPanel); if( routeClickHandler ) { w.click(function() { routeClickHandler(route,stop); }); } }); } }; return that; }(); /* * Copyright (C) 2011 Brian Ferris * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ var OBA = window.OBA || {}; /******************************************************************************* * Map Methods NEW ******************************************************************************/ var obaMapMarkerManagerFactory = function(map) { var that = {}; var markersByZoomLevel = {}; var prevZoomLevel = map.getZoom(); /**** * Private Methods ****/ var refreshMarkerEntry = function() { var zoomLevel = map.getZoom(); var marker = this.marker; var shouldBeVisible = this.zoomFrom <= zoomLevel && zoomLevel < this.zoomTo && ! marker.remove; var isVisible = marker.getVisible(); if( isVisible == undefined ) isVisible = false; if( isVisible != shouldBeVisible ) marker.setVisible(shouldBeVisible); }; /**** * Public Methods ****/ that.addMarker = function(marker, zoomFrom, zoomTo) { if( zoomTo == undefined ) zoomTo = 20; var entry = { 'marker': marker, 'zoomFrom': zoomFrom, 'zoomTo': zoomTo, 'refreshMarkerEntry': refreshMarkerEntry }; marker.obaMarkerManagerEntry = entry; var addMarkerEntryForZoomLevel = function(zoom,entry) { var markersForZoomLevel = markersByZoomLevel[zoom]; if( ! markersForZoomLevel ) { markersForZoomLevel = new Array(); markersByZoomLevel[zoom] = markersForZoomLevel; } markersForZoomLevel.push(entry); }; for(var zoom=zoomFrom; zoom < zoomTo; zoom++) { addMarkerEntryForZoomLevel(zoom, entry); } marker.setMap(map); entry.refreshMarkerEntry(); }; that.removeMarker = function(marker) { var entry = marker.obaMarkerManagerEntry; if( entry == undefined ) return; delete marker.obaMarkerManagerEntry; /** * Removal of the entry from the 'markersByZoomLevel' object is delayed * until the next iteration of a zoom level. See 'refreshEntries()' for * details. */ entry.remove = true; entry.refreshMarkerEntry(); }; that.refresh = function() { var zoomLevel = map.getZoom(); console.log('zoom level changed=' + zoomLevel + ' prevZoomLevel=' + prevZoomLevel); var markersForPrevZoomLevel = markersByZoomLevel[prevZoomLevel]; if( markersForPrevZoomLevel) { console.log(' markersForPrevZoomLevel=' + markersForPrevZoomLevel.length); refreshEntries(markersForPrevZoomLevel); } var markersForZoomLevel = markersByZoomLevel[zoomLevel]; if( markersForZoomLevel) { console.log(' markersForZoomLevel=' + markersForZoomLevel.length); refreshEntries(markersForZoomLevel); } prevZoomLevel = zoomLevel; }; google.maps.event.addListener(map, 'zoom_changed', function(){ that.refresh(); }); var refreshEntries = function(entries) { var writeIndex = 0; for( var readIndex=0; readIndex < entries.length; readIndex++) { var entry = entries[readIndex]; /** * If the entry is marked for removal, we skip it */ if( entry.remove ) continue; entry.refreshMarkerEntry(); /** * Do we need to copy an entry forward? */ if( readIndex != writeIndex) { entries[writeIndex] = entry; } writeIndex++; } // Remove any trailing elements if( writeIndex < entries.length ) { entries.splice(writeIndex,entries.length - writeIndex); } }; return that; }; var obaMapFactory = function() { var that = {}; const RADIUS_OF_EARTH_IN_KM = 6371.01; /**** * Public Methods ****/ that.markerManager = obaMapMarkerManagerFactory; that.map = function(element, params) { params = params || {}; if( element instanceof jQuery ) element = element.get(0); var lat = params.lat || OBA.Config.mapCenterLat|| 47.606828; var lon = params.lon || OBA.Config.mapCenterLon || -122.332505; var zoom = params.zoom || OBA.Config.mapZoom || 10; var mapCenter = new google.maps.LatLng(lat, lon); var mapOptions = { zoom : zoom, center : mapCenter, mapTypeId : google.maps.MapTypeId.ROADMAP }; var map = new google.maps.Map(element, mapOptions); if(OBA.Config.mapBounds) { var swCorner = new google.maps.LatLng(OBA.Config.mapBounds.swLat, OBA.Config.mapBounds.swLon); var neCorner = new google.maps.LatLng(OBA.Config.mapBounds.neLat, OBA.Config.mapBounds.neLon); var bounds = new google.maps.LatLngBounds(swCorner, neCorner); map.fitBounds(bounds); } return map; }; that.mapReady = function(map,callback) { if( map.getProjection() != null ) { callback(); return; } var listener = google.maps.event.addListener(map, 'projection_changed', function() { google.maps.event.removeListener(listener); callback(); }); }; that.decodePolyline = function(encoded) { var len = encoded.length; var index = 0; var array = []; var lat = 0; var lng = 0; while (index < len) { var b; var shift = 0; var result = 0; do { b = encoded.charCodeAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); var dlat = ((result & 1) ? ~(result >> 1) : (result >> 1)); lat += dlat; shift = 0; result = 0; do { b = encoded.charCodeAt(index++) - 63; result |= (b & 0x1f) << shift; shift += 5; } while (b >= 0x20); var dlng = ((result & 1) ? ~(result >> 1) : (result >> 1)); lng += dlng; var point = new google.maps.LatLng(lat * 1e-5, lng * 1e-5); array.push(point); } return array; }; var encodeNumber = function(num) { var encodeString = ''; while (num >= 0x20) { var nextValue = (0x20 | (num & 0x1f)) + 63; encodeString += (String.fromCharCode(nextValue)) num >>= 5; } num += 63; encodeString += (String.fromCharCode(num)) return encodeString; }; var encodedSignedNumber = function(num) { var sgn_num = num << 1; if (num < 0) { sgn_num = ~(sgn_num); } return (encodeNumber(sgn_num)); }; that.encodePolyline = function(points) { var encoded = ''; var pLat = 0; var pLng = 0; for( var index = 0; index