Skip to content

Commit

Permalink
Formatting updates
Browse files Browse the repository at this point in the history
- Removes clearMarkers method, which is only needed if the map results
are updated via ajax (which isn’t currently used)
- Removes the metadata and summary text variables, which were no longer
used.
- Adds additional code comments.
- Moves info window styles from JS to CSS.
- Configures info window states using a bit mask.
- Configures jshint task to allow bitwise operations.
  • Loading branch information
anselmbradford committed Jul 4, 2014
1 parent 19890f9 commit 770efdb
Show file tree
Hide file tree
Showing 4 changed files with 280 additions and 108 deletions.
275 changes: 170 additions & 105 deletions app/assets/javascripts/result/result-map-manager.js.erb
Original file line number Diff line number Diff line change
@@ -1,37 +1,69 @@
//= depend_on_asset 'markers/human_services.png'
// manages results maps view
define(['domReady!',
'async!https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false!callback'], function () {
// Manages results maps view.
define(['util/bitmask','domReady!',
'async!https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false!callback'], function (bitmask) {
'use strict';

require(['http://google-maps-utility-library-v3.googlecode.com/svn/tags/infobox/1.1.9/src/infobox.js'],
require(['https://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox_packed.js'],
function() {

// PRIVATE PROPERTIES
var _map; // the map div that the Google map loads into
var _mapCanvas; // the parent element of _map
var _mapViewControl; // the element that controls the expanding/contracting of the map
var _atMaxSize = false; // whether the map is at its max size or not
// The <div> element that the Google map loads into.
var _map;

var _markerData; // markers on the map
var _markersArray = []; // array for storing markers
var _markerBounds; // the bounds of the markers
// The parent HTML element of the map.
var _mapCanvas;

// constants for map button text content
// The element that controls the expanding/contracting of the map.
var _mapViewControl;

// Whether the map is at its max size or not.
var _atMaxSize = false;

// Parsed JSON object of map marker data (positioning, label, etc.).
var _markerData;

// The collective map bounds of the markers.
var _markerBounds;

// "Constants" for map button text content.
var LARGER_MAP_TEXT = "<i class='fa fa-minus-square'></i> Smaller map";
var SMALLER_MAP_TEXT = "<i class='fa fa-plus-square'></i> Larger map";
var DEFAULT_INFOWINDOW_DELAY = 200;

var _infoWindow; // info window to pop up on roll over
var _infoWindowSelected = false; // whether infowindow is showing or not.
var _overInfoWindow = false;
var _selectedMarker; // the marker that's currently clicked.
// "Constant" for delay when showing/hiding the marker info box.
var DEFAULT_infoBox_DELAY = 400;

// The info box to pop up when rolling over a marker.
var _infoBox;

// A bitmask instance for tracking the different states of the infobox.
var _infoBoxState;

// The possible conditions that determine the infobox's behavior.
var SHOW_INFOBOX = 1;
var OVER_INFOBOX = 2;
var OVER_MARKER = 4;
var PIN_INFOBOX = 8;

// The timer for delaying the info box display.
var _infoBoxDelay;

// The marker that is currently clicked.
var _selectedMarker;

// The marker the cursor is currently over.
var _overMarker;

// The marker InfoBox content that is currently showing.
var _infoBoxContent;

// PUBLIC METHODS
function init()
{
_infoBoxState = bitmask.create();

// Only check for result map if the page isn't showing the no search results view.
var noResults = document.querySelector("#results-entries .no-results");
// only check for result map if the page isn't showing no results
if (!noResults)
{
var mapContainer = document.getElementById('map-view');
Expand All @@ -55,28 +87,21 @@ define(['domReady!',
mapTypeId: google.maps.MapTypeId.ROADMAP
};

_map = new google.maps.Map(_mapCanvas, mapOptions);

var infoBoxOptions = {
disableAutoPan: false,
maxWidth: 0,
pixelOffset: new google.maps.Size(11, -17),
pixelOffset: new google.maps.Size(8, -10),
zIndex: null,
boxStyle: {
backgroundColor: "white",
borderRadius: "4px",
border: "1px solid #bdc3c7",
padding: "3px 6px",
opacity: 0.95
},
infoBoxClearance: new google.maps.Size(1, 1),
isHidden: false,
closeBoxMargin: "5px 2px 2px 2px",
pane: "floatPane",
closeBoxURL: '',
pane: 'floatPane',
enableEventPropagation: false
};

_map = new google.maps.Map(_mapCanvas, mapOptions);

_infoWindow = new InfoBox(infoBoxOptions);
_infoBox = new InfoBox(infoBoxOptions);

_mapViewControl.addEventListener('click', _mapViewControlClicked, false);

Expand All @@ -90,9 +115,8 @@ define(['domReady!',
}
}

// map view control clicked
function _mapViewControlClicked(evt)
{
// Map view control was clicked. This control toggles the large and small maps.
function _mapViewControlClicked(evt) {
if (_atMaxSize)
{
_mapCanvas.classList.remove('max');
Expand All @@ -110,43 +134,81 @@ define(['domReady!',
evt.preventDefault();
}

// loads markers
// Loads the map markers.
function _loadMarkers()
{
var locations = document.getElementById("map-locations");
if (locations)
{
// Load the map marker data from the JSON map data embedded in the DOM.
_markerData = JSON.parse(locations.innerHTML);
locations.parentNode.removeChild(locations); // remove script element
_markerBounds = new google.maps.LatLngBounds();

_clearMarkers();
// Remove the script element from the DOM
locations.parentNode.removeChild(locations);
_markerBounds = new google.maps.LatLngBounds();

var dataLength = _markerData.length;
for(var m = 0; m<dataLength-1; m++)
var index = _markerData.length-1;
var marker;
while(index>=0)
{
_loadMarker( _markerData[m] );
marker = _loadMarker( _markerData[index--] );
}
var metadata = _markerData[dataLength-1];
var summaryText = "<span>"+metadata.count+" of "+metadata.total+" results located!</span>";
}
else
{
// no entries found
_clearMarkers();

_overMarker = marker;

// Register events for info box interactivity.
google.maps.event.addListener(_infoBox, 'domready', function() {
var contentDiv = _mapCanvas.querySelector('.infoBox');
var buttonClose = contentDiv.querySelector('.button-close');
contentDiv.addEventListener('mousemove', _overInfoBoxHandler, false);
contentDiv.addEventListener('mouseleave', _leaveInfoBoxHandler, false);
buttonClose.addEventListener('mousedown', _closeInfoBoxHandler, false);
});
}
}

// clears all markers
function _clearMarkers()
{
for (var i = 0; i < _markersArray.length; i++ ) {
_markersArray[i].setMap(null);
function _overInfoBoxHandler(evt) {
_infoBoxState.turnOn(OVER_INFOBOX);
_updateInfoBoxState();
}

function _leaveInfoBoxHandler(evt) {
_infoBoxState.turnOff(OVER_INFOBOX);
_updateInfoBoxState();
}

function _closeInfoBoxHandler(evt) {
_infoBoxState.turnOff(OVER_INFOBOX);
_infoBoxState.turnOff(SHOW_INFOBOX);
_infoBoxState.turnOff(PIN_INFOBOX);
_updateInfoBoxState(0);
}

function _updateInfoBoxState(delay) {

// Clear any transitions in progress.
if (_infoBoxDelay) clearTimeout(_infoBoxDelay);

// If delay is not set use the default delay value.
var setDelay = delay !== undefined ? delay : DEFAULT_infoBox_DELAY;

if ( _infoBoxState.isOn(OVER_MARKER) ) {
if ( _infoBoxState.isOff(SHOW_INFOBOX) ) {
_openInfoBox(setDelay);
}
else if (_infoBox.getContent() !== _infoBoxContent ) {
_openInfoBox(setDelay);
}
}
else if ( _infoBoxState.isOff(PIN_INFOBOX) &&
_infoBoxState.isOff(OVER_INFOBOX) &&
_infoBoxState.isOff(OVER_MARKER) ) {
_closeInfoBox(setDelay);
}
_markersArray = [];
}

// load a single marker
// Load a single map marker.
// @returns [Object] A google.maps.Marker instance that was created.
function _loadMarker(markerData)
{
if (markerData['coordinates'] && markerData['coordinates'][0] && markerData['coordinates'][1])
Expand All @@ -164,86 +226,89 @@ define(['domReady!',
optimized: false
});

_markersArray.push(marker);

var agency = markerData['agency'] ? "<h2>"+markerData['agency']+"</h2>" : "";
var content = "<h1 style='font-weight: bold;'>"+markerData['name']+"</h1>"+agency+
"<p><a href='/organizations/"+marker.id+(window.location.search)+
"'>Click to view details.</a></p>";
var content = "<div><div class='button-close'></div><h1>"+markerData['name']+"</h1>"+agency+
"<p><a href='/organizations/"+marker.id+(window.location.search)+
"'>View more details</a></p></div>";

_makeInfoWindowEvent(_map, _infoWindow, content, marker);
_makeInfoBoxEvent(marker, content);

_markerBounds.extend(myLatlng);

}

return marker;
}

function _openInfoWindow(marker,content)
// Open the global info box after a delay.
// @param delay [Number] Delay in milliseconds before opening the info box.
// If not specified, the delay will be the DEFAULT_infoBox_DELAY value.
function _openInfoBox(delay)
{
if (!_infoWindowSelected) {
setTimeout(function() {
_infoWindow.setContent(content);
_infoWindow.open(_map, marker);
}, DEFAULT_INFOWINDOW_DELAY);
}
_infoBoxDelay = setTimeout(function() {
_infoBox.setContent(_infoBoxContent);
_infoBox.open(_map, _selectedMarker);
_infoBoxState.turnOn(SHOW_INFOBOX);
}, delay);
}

function _closeInfoWindow()
// Open the global info box after a delay.
// @param delay [Number] Delay in milliseconds before closing the info box.
// If not specified, the delay will be the DEFAULT_infoBox_DELAY value.
function _closeInfoBox(delay)
{
setTimeout(function() {
if (!_infoWindowSelected && !_overInfoWindow) {
_infoWindow.close();
}
}, DEFAULT_INFOWINDOW_DELAY);
_infoBoxDelay = setTimeout(function() {
_infoBox.close();
_infoBoxState.turnOff(SHOW_INFOBOX);
}, delay);
}

// make info window events associated with this marker
function _makeInfoWindowEvent(map, infowindow, content, marker) {
var contentDiv;
google.maps.event.addListener(_infoWindow, 'domready', function() {
contentDiv = _mapCanvas.querySelector('.infoBox');
contentDiv.addEventListener('mousemove',function(evt){ _overInfoWindow = true; });
contentDiv.addEventListener('mousedown',function(evt){ _infoWindowSelected = true; });
contentDiv.addEventListener('mouseleave',function(evt){ _overInfoWindow = false; _closeInfoWindow(); });
// Make info box events associated with a map marker.
// @param marker [Object] The marker that triggered the opening of the info box.
// @param content [String] The text content of the info box.
function _makeInfoBoxEvent(marker, content) {

// When user mouses over the marker, open the infoBox and update its contents.
google.maps.event.addListener(marker, 'mouseover', function() {
if (_overMarker !== marker) _infoBoxState.turnOff(PIN_INFOBOX);
_overMarker = marker;
_infoBoxState.turnOn(OVER_MARKER);
_infoBoxContent = content;
_selectedMarker = marker;
_updateInfoBoxState();
});
google.maps.event.addListener(marker, 'mouseout', function() {
_infoBoxState.turnOff(OVER_MARKER);
_updateInfoBoxState();
});

// when user mouses over the marker, open the infoBox and update its contents
google.maps.event.addListener(marker, 'mouseover', function(evt) { _openInfoWindow(marker,content); });

google.maps.event.addListener(marker, 'mouseout', function() { _closeInfoWindow(); });

// when user clicks the marker, open the infoBox and center the map on the marker
// When user clicks the marker, open the infoBox and center the map on the marker
google.maps.event.addListener(marker, 'click', function() {
if (_selectedMarker === marker)
if (_infoBoxState.isOn(PIN_INFOBOX))
{
_infoWindow.close();
_infoWindowSelected = false;
_selectedMarker = undefined;
_infoBoxState.turnOff(SHOW_INFOBOX);
_infoBoxState.turnOff(PIN_INFOBOX);
_infoBoxState.turnOff(OVER_MARKER);
_updateInfoBoxState(0);
}
else
{

_infoWindow.open(map, marker)
_infoWindowSelected = true;
_selectedMarker = marker;
map.panTo(marker.position);
_map.panTo(marker.position);
_infoBoxState.turnOn(PIN_INFOBOX);
_infoBoxState.turnOn(OVER_MARKER);
_updateInfoBoxState(0);
}
});

google.maps.event.addListener(_infoWindow,'closeclick', function() {
_infoWindowSelected = false;
})
}

// Triggers a resize event and refits the map to the bounds of the markers
function _refresh()
{
google.maps.event.trigger(_map, "resize");
if (_markersArray.length > 0)
_map.fitBounds(_markerBounds);
_map.fitBounds(_markerBounds);
}

init(); // makes the module initialization self-executing once dependencies have loaded.
// Makes the module initialization self-executing once dependencies have loaded.
init();
});

});

0 comments on commit 770efdb

Please sign in to comment.