Reputation: 11035
I'm using the Google Maps Places Library to work on something similar to the following: http://codepen.io/maudulus/pen/oxNXod. As you can see, when you load the page there are a number of markers that can be filtered using the State select
. You can also use the search box to find markers within one standard deviation of the location you search.
However, I'm trying to combine these two features (for example, someone searches for a location, and then filters the results by state). I'm not sure why this doesn't currently work...my guess is that it might be double-adding points, because it does seem to be wanting to filter locations (you can see them flicker when you change the select
).
LOCATION CODE
var map;
var originalStores = [];
var markersArr = [];
var geocoder = new google.maps.Geocoder();
var typingTimer; //timer identifier
var doneTypingInterval = 1000; //time in ms, 5 second for example
var $location = $('#location');
$location.on('keyup', function(e) {
clearTimeout(typingTimer);
typingTimer = setTimeout(queryLocation, doneTypingInterval);
});
$location.on('keydown', function() {
clearTimeout(typingTimer);
});
function queryLocation(urlParamLocation) {
var queryingLocation = (urlParamLocation) ? urlParamLocation : $('#location').val();
getLatLong(queryingLocation, function(discoveredLatLng) {
replotMap(discoveredLatLng);
});
}
function getLatLong(address, cb) {
var tempCurrentPosition = {
latitude: "",
longitude: ""
};
geocoder.geocode({
'address': address
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
tempCurrentPosition.latitude = results[0].geometry.location.lat();
tempCurrentPosition.longitude = results[0].geometry.location.lng();
cb(tempCurrentPosition);
}
});
}
function replotMap(locationValue) {
if (locationValue) {
$.each(originalStores, function(index, thisLocale) {
thisLocale.distance = getDistanceFromLatLon(locationValue.latitude, locationValue.longitude, thisLocale.latitude, thisLocale.longitude);
});
var sdCompliant = withinOneSD(originalStores, standardDeviation(originalStores));
addMapMarkers(sdCompliant);
}
}
function initialize() {
var input = document.getElementById('location');
var autocomplete = new google.maps.places.Autocomplete(input);
}
initialize();
function initializeMap() {
var myLatlng = new google.maps.LatLng(39.768408, -86.157975);
var mapOptions = {
zoom: 7,
center: myLatlng,
scrollwheel: false,
navigationControl: false,
mapTypeControl: false,
scaleControl: false,
draggable: true,
};
map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
plotAllMarkers();
}
initializeMap();
function plotAllMarkers() {
removeExtraneousMarkers();
$.each($('#locations-ul li'), function(index, store) {
var thisStoreObj = {};
thisStoreObj.Address = $(store).attr('address');
thisStoreObj.latitude = $(store).attr('data-latitude');
thisStoreObj.longitude = $(store).attr('data-longitude');
thisStoreObj.Store = $(store).attr('data-store');
thisStoreObj.distance = "";
originalStores.push(thisStoreObj);
});
originalStores = originalStores.sort(compare);
$.each(originalStores, function(index, thisStore) {
if (thisStore.Store) {
plotTableRow(thisStore);
}
});
addMapMarkers(originalStores);
}
function addMapMarkers(arr, allArr) {
removeExtraneousMarkers();
deleteMarkers();
var bounds = new google.maps.LatLngBounds();
$.each(arr, function(index, thisLocation) {
plotTableRow(thisLocation);
var currentState = findState(thisLocation.Address);
var currLatlng = new google.maps.LatLng(thisLocation.latitude, thisLocation.longitude);
var marker = new google.maps.Marker({
position: currLatlng,
map: map,
title: thisLocation.Store,
state: currentState
});
markersArr.push(marker);
});
for (var i = 0; i < markersArr.length; i++) {
bounds.extend(markersArr[i].getPosition());
}
map.fitBounds(bounds);
adjustPlottedMarkersToBounds(markersArr);
}
function filterByState(stateMarkerArr) {
$('#state-select').on('change', function() {
var stateCode = $(this).val();
$('.locations-table .locations-div').hide();
$.each($('.locations-table .locations-div.filtered-location'), function(index, thisLocation) {
var addressText = $(thisLocation).find('h4').text();
if (addressText.indexOf(stateCode) > -1) {
$(thisLocation).show();
}
});
clearMarkers();
$.each(stateMarkerArr, function(index, thisStateMarker) {
if (thisStateMarker.state == stateCode) {
thisStateMarker.setMap(map);
}
});
});
}
function adjustPlottedMarkersToBounds(allArr) {
google.maps.event.addListener(map, 'bounds_changed', function() {
removeExtraneousMarkers();
var markersArrStateFilter = [];
for (var i = 0; i < allArr.length; i++) {
if (map.getBounds().contains(allArr[i].getPosition())) {
// markers[i] in visible bounds
markersArrStateFilter.push(allArr[i]);
allArr[i].setMap(map);
$.each(originalStores, function(index, thisStore) {
if (thisStore.Store == allArr[i].title) {
plotTableRow(thisStore, "filtered-location");
}
});
} else {
// markers[i] is not in visible bounds
allArr[i].setMap(null);
}
}
filterByState(markersArrStateFilter);
});
};
function removeExtraneousMarkers() {
$('.locations-div').remove()
$('#state-select').val('').change();
}
// Sets the map on all markers in the array.
function setMapOnAll(map) {
for (var i = 0; i < markersArr.length; i++) {
markersArr[i].setMap(map);
}
}
// Removes the markers from the map, but keeps them in the array.
function clearMarkers() {
setMapOnAll(null);
}
function deleteMarkers() {
clearMarkers();
markersArr = [];
}
function findState(subStr) {
if (subStr.indexOf('OH') > -1) {
return 'OH';
} else if (subStr.indexOf('IL') > -1) {
return 'IL';
} else if (subStr.indexOf('MO') > -1) {
return 'MO';
} else if (subStr.indexOf('MI') > -1) {
return 'MI';
} else if (subStr.indexOf('IN') > -1) {
return 'IN';
}
}
function plotTableRow(thisStore, addedClass) {
$('.locations-table').append('<div class="columns small-12 medium-6 locations-div ' + addedClass + '"><div class="row"><div class="columns small-3"><img src="https://cdn1.iconfinder.com/data/icons/mirrored-twins-icon-set-hollow/512/PixelKit_point_marker_icon.png"></div><div class="columns small-9"><h3>Marker</h3><h4>' + thisStore.Address + '</h4></div></div></div>');
};
APPENDIX CODE:
function compare(a, b) {
if (a.distance < b.distance)
return -1;
if (a.distance > b.distance)
return 1;
return 0;
}
function getDistanceFromLatLon(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1); // deg2rad below
var dLon = deg2rad(lon2 - lon1);
var a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c; // Distance in km
return getMiles(d);
}
function deg2rad(deg) {
return deg * (Math.PI / 180)
}
//converts to miles
function getMiles(i) {
return i * 0.621371192;
}
function withinOneSD(arr, sd) {
var tempArr = [];
var arrMax = Math.max.apply(Math, numArr);
var arrMin = Math.min.apply(Math, numArr);
$.each(arr, function(index, currValue) {
if (currValue.distance <= (arrMin + sd)) {
tempArr.push(currValue);
}
});
return tempArr;
}
var numArr;
function standardDeviation(values) {
numArr = [];
$.each(values, function(index, currentValue) {
numArr.push(currentValue.distance);
})
var avg = average(numArr);
var squareDiffs = numArr.map(function(value) {
var diff = value - avg;
var sqrDiff = diff * diff;
return sqrDiff;
});
var avgSquareDiff = average(squareDiffs);
var stdDev = Math.sqrt(avgSquareDiff);
return stdDev;
}
function average(data) {
var sum = data.reduce(function(sum, value) {
return sum + value;
}, 0);
var avg = sum / data.length;
return avg;
}
See it here: http://codepen.io/maudulus/pen/oxNXod
Upvotes: 0
Views: 1163
Reputation: 161384
One problem is this code, which only shows markers, doesn't hide them if they don't match the state, doesn't seem like clearMarkers
is doing what you think:
function filterByState(stateMarkerArr) {
$('#state-select').on('change', function() {
var stateCode = $(this).val();
$('.locations-table .locations-div').hide();
$.each($('.locations-table .locations-div.filtered-location'), function(index, thisLocation) {
var addressText = $(thisLocation).find('h4').text();
if (addressText.indexOf(stateCode) > -1) {
$(thisLocation).show();
}
});
clearMarkers();
$.each(stateMarkerArr, function(index, thisStateMarker) {
if (thisStateMarker.state == stateCode) {
thisStateMarker.setMap(map);
}
});
});
}
Add an else to the if (thisStateMarker.state == stateCode) {
function filterByState(stateMarkerArr) {
$('#state-select').on('change', function() {
var stateCode = $(this).val();
$('.locations-table .locations-div').hide();
$.each($('.locations-table .locations-div.filtered-location'), function(index, thisLocation) {
var addressText = $(thisLocation).find('h4').text();
if (addressText.indexOf(stateCode) > -1) {
$(thisLocation).show();
}
});
clearMarkers();
$.each(stateMarkerArr, function(index, thisStateMarker) {
if (thisStateMarker.state == stateCode) {
thisStateMarker.setMap(map);
} else {
thisStateMarker.setMap(null);
}
});
});
}
Upvotes: 1