I've successfully implemented angular-google-maps on a local project of mine with list of markers that's being put on my map.
But how can I get the "Visible Markers In Bounds"? (the angular-way)
jQuery example: http://jsfiddle.net/glafarge/mbuLw/
At the moment I've attached an event inside my controller on "idle" which gets triggered whenever map changes (zoom et). The foreach loops through my markers, but I'm just not sure how to perform the "contains(marker.getPosition())" because that's not a function in the angular version of google maps.
events: {
idle: function () {
console.log("change triggered");
angular.forEach($scope.markers, function(marker, key) {
console.log("set visible markers here");
});
}
}
Bounds are accessible in $scope.map.bounds and looks like this:
$scope.map.bounds = {
northeast: {
latitude: 51.219053,
longitude: 4.404418
},
southwest: {
latitude: -51.219053,
longitude: -4.404418
}
}
The map object is accessible in $scope.mapRef:
uiGmapIsReady.promise().then(function (map_instances) {
$scope.mapRef = $scope.map.control.getGMap();
});
Inspired by MayK's answer I solved it with the following:
idle: function (map) {
$timeout(function() {
var visibleMarkers = [];
angular.forEach($scope.markers, function(marker, key) {
if ($scope.map.bounds.southwest.latitude < marker.coords.latitude
&& marker.coords.latitude < $scope.map.bounds.northeast.latitude
&& $scope.map.bounds.southwest.longitude < marker.coords.longitude
&& marker.coords.longitude < $scope.map.bounds.northeast.longitude) {
visibleMarkers.push(marker);
}
});
$scope.visibleMarkers = visibleMarkers;
}, 0);
}
add an events for bounds_changed whenever there is a change, iterate over your markers: for each marker if this condition (bounds.sw.lat< marker.lat < bounds.ne.lat and bounds.sw.lon < marker.lon < bounds.ne.lon ) is true, then your marker is visible, so you can append it to a list of visible markers.
vm.map.events = {
bounds_changed: function(map) {
vm.visibleMarkers=[];
for (var i = 0; i < vm.beaconMarkers.length; i++) {
if (vm.map.bounds.southwest.latitude < vm.beaconMarkers[i].latitude && vm.beaconMarkers[i].latitude < vm.map.bounds.northeast.latitude && vm.map.bounds.southwest.longitude < vm.beaconMarkers[i].longitude && vm.beaconMarkers[i].longitude< vm.map.bounds.northeast.longitude) {
vm.visibleMarkers.push(
vm.beaconMarkers[i]
);
}
}
}
};
Sadly I just discovered a bug in the "accepted solution". If you for example drag your map northeast of Asia it will return a negative longitude which makes the condition return false.
For now I resolved it by using google maps build-in functionality like beneath. However though, I don't think this is the best approach so I'm still looking for a better approach:
var visibleMarkers = [];
var bounds = $scope.mapRef.getBounds();
angular.forEach($scope.markers, function(marker, key) {
var gMarker = new google.maps.Marker({
position: {
lat: marker.coords.latitude,
lng: marker.coords.longitude
}
});
if(bounds.contains(gMarker.getPosition())===true) {
visibleMarkers.push(marker);
}
});
$scope.visibleMarkers = visibleMarkers;
Used Map Object's getBounds() method then use contains() method to detect whether the lat lng is within bound
Related
I have a react-google-maps instance in my application which draws multiple location icons on google map. When there are more than one icons, sometimes, one icon, which have different location, gets stuck on another icon. The new icon is not clickable and gets removed automatically after giving a little nudge to the map (see image below)
IMO, the issue is with the google map's drawing multiple location icons.
Any idea, how can I fix this?
Here's how I am setting state when the component mounts
this.state = this.convertEntityStructureToComponentState(props.entities, props.hideInfoInitially, props.showDirections);
convertEntityStructureToComponentState() function looks like this:
convertEntityStructureToComponentState(entities, hideInfoInitially, showDirections=false) {
if (!entities || entities.length === 0) {
// send seattle longitude and latitude and set markers as null
const center = {
lat: 47.602743,
lng: -122.330626
};
return {
center: center,
markers: []
};
}
const markers = [];
let firstEntityReadings = null;
let destinationPosition = null;
let selectedEntityPosition = null;
let showPathLine = true;
for (let i = 0; i < entities.length; i++) {
if (entities[i].location) {
if (!firstEntityReadings) {
firstEntityReadings = {
lat: entities[i].location.lat,
lng: entities[i].location.lng
};
}
let showLocation = true;
if (entities[i].type === 'customer') {
destinationPosition = i;
} else {
if (this.isTimeInOnlineRange(entities[i].time)) {
selectedEntityPosition = i;
} else if (this.props.customerView) {
showLocation = false;
showPathLine = false;
}
}
if (showLocation) {
markers.push({
position: new google.maps.LatLng(entities[i].location.lat, entities[i].location.lng),
showInfo: false,
data: {
name: entities[i].name,
address: entities[i].address,
id: entities[i].id,
time: entities[i].time,
color: entities[i].type === 'customer' ? entities[i].color : '#ccc',
type: entities[i].type,
image_path: entities[i].image_path
}
});
}
}
}
//Optimize where we get previous location and don't call direction if it's the same
if (showDirections && destinationPosition != null && selectedEntityPosition != null && showPathLine) {
const DirectionsService = new google.maps.DirectionsService();
DirectionsService.route({
origin: new google.maps.LatLng(entities[selectedEntityPosition].location.lat, entities[selectedEntityPosition].location.lng),
destination: new google.maps.LatLng(entities[destinationPosition].location.lat, entities[destinationPosition].location.lng),
travelMode: google.maps.TravelMode.DRIVING,
}, (result, status) => {
if (status === google.maps.DirectionsStatus.OK) {
this.setState({
directions: result
});
}
});
} else {
this.setState({
directions: null
});
}
return {
center: firstEntityReadings,
markers: markers
};
}
Link to Github issue: https://github.com/tomchentw/react-google-maps/issues/805
Link to the gist of location map component: https://gist.github.com/arximughal/f91b7a922a4711e25ef82ed9ac6427b5
The issue was with the key and ref of the markers that I was drawing on the map. Generating a random ID for key fixed the issue properly.
I have a simple AngularJs application of medical cards.
I have storage with it and display it at my home.html using dx-datagrid:
One card has many records, I get records of card from recordsArray by cardId
getVardsRecordsByCardId: function (id, recordsArray) {
if (recordsArray.length != 0) {
for (var i = 0; i < recordsArray.length; i++) {
if (recordsArray[i].cardId === id) {
cardsRecords = cardsRecords.concat(recordsArray[i]);
}
}
}
return cardsRecords;
}
Now I have records just in the third card. I added a function on button for testing it:
var jdskla = [];
var localCardId = 0;
$scope.showCardDetails = {
text: "",
type: "default",
icon: "preferences",
onClick: function () {
if ($scope.itemIdFromShowButton) {
$location.path('/carddetail/' + $scope.itemIdFromShowButton);
var jdskla =[];
var jdskla = businessLogicOfMyApp.getVardsRecordsByCardId($scope.itemIdFromShowButton, $scope.recordsArray);
console.log($scope.itemIdFromShowButton)
console.log(jdskla);
}
else {
alert("Error!!!");
}
}
};
1,3,1 is cardId's and array of records. But, why array of card records don't clears and save last data?
May be somebody know how I can resolve it? Thanks for your answers!
P.S. I'm using ng-view directive in my app and i tried to clear my array use another button:
$scope.backToGeneralPage = {
text: "Back",
onClick: function () {
jdskla = [];
$location.path('/');
}
};
but it wasn't helpful.
You should initialize cardsRecords array in function getVardsRecordsByCardId.
getVardsRecordsByCardId: function (id, recordsArray) {
var cardsRecords = []; // initialize array locally
if (recordsArray.length != 0) {
for (var i = 0; i < recordsArray.length; i++) {
if (recordsArray[i].cardId === id) {
cardsRecords.push(recordsArray[i]);
}
}
}
return cardsRecords;
}
I am adding 'place_changed' listener it's not working first time when I search the address while it's working perfectly afterwards. Can anyone tell me what should be done. here is my code. Thanks in advance for your support
var events = {
places_changed: function (searchBox) {
var gPlace = new google.maps.places.Autocomplete(document.getElementById('map-search-box'));
google.maps.event.addListener(gPlace, 'place_changed', function() {
var place = gPlace.getPlace();
var a =place.geometry.location;
$scope.myLocation = {
lng : place.geometry.location.D,
lat: place.geometry.location.k
}
abc = {
coords: {
latitude: place.geometry.location.k,
longitude:place.geometry.location.D
}
}
$scope.drawMap(abc);
});
}
}
Thanks KayAnn I have solved the issue. Actually I never checked in the function (searchBox) {} searchBox it's object which were proving all the data I required so here is updated code that is working perfectly
var events = {
places_changed: function (searchBox) {
var lat = searchBox.getPlaces()[0].geometry.location.k;
var lgn = searchBox.getPlaces()[0].geometry.location.D;
$scope.myLocation = {
lng : searchBox.getPlaces()[0].geometry.location.D,
lat: searchBox.getPlaces()[0].geometry.location.k
}
abc = {
coords: {
latitude: searchBox.getPlaces()[0].geometry.location.k,
longitude:searchBox.getPlaces()[0].geometry.location.D
}
}
$scope.drawMap(abc); } }
I'm rattling my brains here and cannot figure out why this is not working
var lat = Math.round(top_location.geometry.location.lat() * 1000000)/1000000;
var lng = Math.round(top_location.geometry.location.lng() * 1000000)/1000000;
geocode_results[i]['lat'] = lat;
geocode_results[i]['lng'] = lng;
geocode_results[i]['l_type'] = top_location.geometry.location_type;
marker = new google.maps.Marker({
icon: mapIcon,
position: new google.maps.LatLng(lat,lng),
map: map
});
markersArray.push(top_location.address_components[0].long_name);
Using the above created my marker(s) and plots them on my map.
Using the following code to remove the markers from the map
$scope.removemarkers = function() {
console.log($scope);
console.log(markersArray);
if (markersArray && markersArray.length) {
for (var i = 0; i < markersArray.length; i++) {
markersArray[i].setMap(null);
}
markersArray = [];
}
};
I get the following error in console.log()
TypeError: Object AB42 2DL has no method 'setMap'at
Object.$scope.removemarkers
AB42 2DL being a random postcode used when plotting a marker
markersArray doesn't contain markers, it contains strings.
Try this:
markersArray.push(marker);
I'm looking for resources that create scrolling functions like the ones found on these sites:
Outpost Journal
Unfold
Once the scroll bar hits the bottom of the page, I want it to loop back to the top.
I'm familiar with with the infinite scroll, and this is not what I want. I've also found scripts that will write/add the same content to the bottom of the page, but none that loop back to the top of the page.
Try this:
$('document').ready(function() {
$(document).scroll(function(){
if(document.documentElement.clientHeight +
$(document).scrollTop() >= document.body.offsetHeight )$(document).scrollTop(0);
});
});
if you want infinite scroll in both directions use
if (document.documentElement.clientHeight + $(window).scrollTop() >= $(document).height()) {
$(document).scrollTop(0)
} else if ($(window).scrollTop() < 0) {
$(document).scrollTop($(document).height())
}
(I know it's a late reply but it still helps users like me who just google stuff like this)
Here a solution that makes a duplicate of the body so the bottom and the top can be seen at the same time at a certain point so the transition is smoother.
$('document').ready(function() {
// We need to duplicate the whole body of the website so if you scroll down you can see both the bottom and the top at the same time. Before we do this we need to know the original height of the website.
var origDocHeight = document.body.offsetHeight;
// now we know the height we can duplicate the body
$("body").contents().clone().appendTo("body");
$(document).scroll(function(){ // detect scrolling
var scrollWindowPos = $(document).scrollTop(); // store how far we have scrolled
if(scrollWindowPos >= origDocHeight ) { // if we scrolled further then the original doc height
$(document).scrollTop(0); // then scroll to the top
}
});
});
mrida's answer was causing my browser to not be able to scroll, here is a modified version that worked for me:
$('document').ready(function() {
$(document).scroll(function(){
if (document.documentElement.clientHeight + $(window).scrollTop() >= $(document).height()) {
$(document).scrollTop(0);
}
});
});
Forked from #clankill3r's answer, create two copy of body, prepend and append to the original body, then you can scroll the page in two direction endless.
$('document').ready(function() {
var origDocHeight = document.body.offsetHeight;
var clone=$("body").contents().clone();
clone.appendTo("body");
clone.prependTo("body");
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(0);
}
if(scrollWindowPos <= 0 ) {
$(document).scrollTop(origDocHeight);
}
});
});
Adding loop scroll backwards, upgrading #clankill3r answer. It should be something like this.
$('document').ready(function() {
// We need to duplicate the whole body of the website so if you scroll down you can see both the bottom and the top at the same time. Before we do this we need to know the original height of the website.
var origDocHeight = document.body.offsetHeight;
// now we know the height we can duplicate the body
$("body").contents().clone().appendTo("body");
$(document).scroll(function(){ // detect scrolling
var scrollWindowPos = $(document).scrollTop(); // store how far we have scrolled
if(scrollWindowPos >= origDocHeight ) { // if we scrolled further then the original doc height
$(document).scrollTop(scrollWindowPos + origDocHeight); // then scroll to the top
} else if (scrollWindowPos == 0) { // if we scrolled backwards
$(document).scrollTop(origDocHeight);
}
});
});
I'm using it horizontally and it's working just fine. Hope someone finds it useful.
Posted a similar question: https://stackoverflow.com/a/65953934/7474712 and found the answer via this pen: https://codepen.io/vincentorback/pen/zxRyzj
Here's the code:
<style>
html,
body {
height: 100%;
overflow: hidden;
}
.infinite {
overflow: auto;
-webkit-overflow-scrolling: touch;
}
.clone {
height: 50vw;
}
</style>
<script>
var doc = window.document,
context = doc.querySelector('.infinite'),
clones = context.querySelectorAll('.clone'),
disableScroll = false,
scrollHeight = 0,
scrollPos = 0,
clonesHeight = 0,
i = 0;
function getScrollPos () {
return (context.pageYOffset || context.scrollTop) - (context.clientTop || 0);
}
function setScrollPos (pos) {
context.scrollTop = pos;
}
function getClonesHeight () {
clonesHeight = 0;
for (i = 0; i < clones.length; i += 1) {
clonesHeight = clonesHeight + clones[i].offsetHeight;
}
return clonesHeight;
}
function reCalc () {
scrollPos = getScrollPos();
scrollHeight = context.scrollHeight;
clonesHeight = getClonesHeight();
if (scrollPos <= 0) {
setScrollPos(1); // Scroll 1 pixel to allow upwards scrolling
}
}
function scrollUpdate () {
if (!disableScroll) {
scrollPos = getScrollPos();
if (clonesHeight + scrollPos >= scrollHeight) {
// Scroll to the top when you’ve reached the bottom
setScrollPos(1); // Scroll down 1 pixel to allow upwards scrolling
disableScroll = true;
} else if (scrollPos <= 0) {
// Scroll to the bottom when you reach the top
setScrollPos(scrollHeight - clonesHeight);
disableScroll = true;
}
}
if (disableScroll) {
// Disable scroll-jumping for a short time to avoid flickering
window.setTimeout(function () {
disableScroll = false;
}, 40);
}
}
function init () {
reCalc();
context.addEventListener('scroll', function () {
window.requestAnimationFrame(scrollUpdate);
}, false);
window.addEventListener('resize', function () {
window.requestAnimationFrame(reCalc);
}, false);
}
if (document.readyState !== 'loading') {
init()
} else {
doc.addEventListener('DOMContentLoaded', init, false)
}
</script>