Remove google maps markers in Angular - javascript

I am using the #angular/google-maps package to display a Google Map with some markers which like this:
map.html
<google-map>
<map-marker
*ngFor="let marker of markers"
[position]="marker.position">
</google-map>
map.ts
#ViewChild(GoogleMap, { static: false }) map!: GoogleMap;
markers = [] as any;
replaceMarker()
{
this.markers = [];
this.markers.push({
position: {
lat: lat,
lng: lng,
},
options: {
animation: google.maps.Animation.DROP,
},
});
}
This is not the code but identical to the implementation. The problem I am having, is that when I try and remove all markers then add a new one, the old markers never remove from the map, they just stay there and the other markers just pile on top.
My question is: How do I remove all markers before pushing my new ones to my markers array?

I was getting my data from an observable so I just had to move this.markers = [] into the subscribe() function

Related

Issues with adding markers with Google Maps Javascript API using React.js

So, I am trying to add a marker on the Google Maps which is part of the functionality of the react.js app I am developing.
const MapCode = document.createElement('script')
MapCode.src =`https://maps.googleapis.com/maps/api/js?key=${process.env.REACT_APP_GOOGLE_MAPS_API_KEY}`
window.document.body.appendChild(MapCode)
MapCode.addEventListener('load', ()=>{
this.initMap()
this.targetedCityMarker()
})
}
initMap(){
new window.google.maps.Map(this.googleMap.current,{
zoom: 7.5,
center:{ lat: this.state.cityCoordinates[1], lng:this.state.cityCoordinates[0] },
disableDefaultUI: true,
})
}
targetedCityMarker(){
console.log('testing')
new window.google.maps.Marker({
position: { lat: this.state.cityCoordinates[1], lng:this.state.cityCoordinates[0] },
map:this.initMap(),
})
}
The issue is, when I run the code, initMap()works . I can see the map on my page with map centre located at the defined coordinate. For the targetedCityMarker, console.log('testing')can be seen, but somehow the Marker part is not showing up. What has gone wrong here?
In your Marker() initialization, you are trying to use this.initMap() as a map instance, however, that function does not return anything.
Try to return the map instance you initialized from that function:
initMap(){
return new window.google.maps.Map(this.googleMap.current,{
zoom: 7.5,
center:{ lat: this.state.cityCoordinates[1], lng:this.state.cityCoordinates[0] },
disableDefaultUI: true,
})
}
and then you'll be able to use it in your Marker() in a way you are doing it now.

view.goTo map renders blank arcgis

I am working on an arcgis map, I'm trying to update the map center by calling goTo() on my mapview but for some reason the map just changes to be blank and never updates, I am logging the new coordinates and they are correct.
I am using the reference docs here: https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html
Can someone with some arcgis experience help me out. I know this isn't an issue with my code specifically but it might be an issue with vue and component rendering as it relates to arcgis
so far I have tried
- getting rid of props and updating everything within the component locally
- using keys to force re-render the component
as an interesting note, if I just enter in some magic numbers for my new location the map updates correctly, however when i use some function to get the location and then pass it in, it does not work and just shows as a blank map
my app.vue
<template>
<div id="app">
<web-map v-bind:centerX="lat" v-bind:centerY="long" ref="map"/>
<div class="center">
<b-button class="btn-block" #click="updateCenter()" variant="primary">My Location</b-button>
</div>
</div>
</template>
<script>
import WebMap from './components/webmap.vue';
export default {
name: 'App',
components: { WebMap },
data(){
return{
lat: null,
long: null,
}
},
methods:{
updateCenter(){
this.$refs.map.getLocation()
}
},
};
</script>
my map component
<template>
<div></div>
</template>
<script>
import { loadModules } from 'esri-loader';
export default {
name: 'web-map',
data: function(){
return{
X: -118,
Y: 34,
}
},
mounted() {
console.log('new data',this.X,this.Y)
// lazy load the required ArcGIS API for JavaScript modules and CSS
loadModules(['esri/Map', 'esri/views/MapView'], { css: true })
.then(([ArcGISMap, MapView]) => {
const map = new ArcGISMap({
basemap: 'topo-vector'
});
this.view = new MapView({
container: this.$el,
map: map,
center: [-118,34], ///USE PROPS HERE FOR NEW CENTER
zoom: 8
});
});
},
beforeDestroy() {
if (this.view) {
// destroy the map view
this.view.container = null;
}
},
methods:{
showPos(pos){
console.log('new location',pos.coords.latitude,pos.coords.longitude)
this.view.goTo({center:[pos.coords.latitude,pos.coords.longitude]})
},
getLocation(){
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(this.showPos);
} else {
console.log("Geolocation is not supported by this browser.");
}
},
}
};
</script>
Switch:
this.view = new MapView({
container: this.$el,
map: map,
center: [-118,34], ///USE PROPS HERE FOR NEW CENTER
zoom: 8
});
to
this.view = new MapView({
container: this.$el,
map: map });
this.view.center.longitude = -118;
this.view.center.latitude = 34;
this.view.zoom = 8;
The other answer by Tao has the long/latitude backwards in the .goTo({center: []}) method call, which is why it goes to the ocean: https://developers.arcgis.com/javascript/latest/api-reference/esri-views-MapView.html#goTo
Here's something that works:
https://codesandbox.io/s/frosty-glitter-39wpe?file=/src/App.vue
I made it from scratch, only taking small bits from yours and combining them with some examples from ArcGIS (which I'm not familiar with, at all).
One thing to note is that the .goTo({center: [lat, long]}) didn't work as expected: it kept centering in the middle of some ocean.
I then imported Point from esri and passed the center as new Point(long, lat), which seems to produce the expected result. Since it works, I haven't looked further, but I guess it should be doable without the conversion. You probably need to pass in the coordinates system or something along these lines.
As far as I can tell, what's wrong in your example is the way you try to pass data down from parent to child. You expect this.$refs.map to be a Vue instance, but it's not. It's a DOM element. It's basically the Vue instance's $el. Accessing child methods from parent instance is not so straight forward.
Another thing to notice is that, even though you bind centerX and centerY on child in your example, you never seem to use them (but I guess that's just a left over from when you tried with props !?).
Anyways, in my example, I chose to simply update the coords prop of the children while having a watch fn to handle re-centering.

insert a url/path into google maps marker, Laravel

I am trying to insert a url/path into google map marker. So I tried google map's url: but no effects. when mouse on the marker it changes to pointer but I can't click or the page doesn't open.
By the way I try to make path to detail screen of each id.
var marker = new google.maps.Marker({
map: map,
icon: 'imgs/marker.png',
label: {
text: estates.data[0].price,
color: "#fff",
},
url: "/pages/{{$est->id}}",
position: {
lat: {{$est->lat}},
lng: {{$est->lng}}
}
});
The way I am using it wrong?
Controller:
public function details($id)
{
$estates = allestates::where('id', $id)->first();
// $rsltActualPrice = (int)$estates->extend / (int)$estates->price;
return view('pages.details', compact('estates'));
}
and Route:
Route::get('/pages/{id}', 'PagesController#details');
You may want to create a route like :
Route::get('/pages/{estateId}', 'yourController#index')->name('map');
and change your url address to this :
url: route('map', ['estateId' => $est->id]),

How to integrate Geodjango with Google Maps API 3?

I have a geodjango queryset containing several fields but want to use only user_name and location (a point field) which I want to use as a marker in google maps API 3.
Bear with me as I don’t know Javascript and I have a series of questions.
Take this as conceptual brainstorming for a novice:
My SO search suggests that I need to serialize the queryset objects
to JSON. I use the built-in serializer module to convert to JSON.
I think the JSON objects are converted in views.py (let’s
call it json_data). Are these JSON objects stored in the PostGIS database? Wouldn’t that be redundant?
Furthermore, how do I reference them in the map.js (google maps
API 3) javascript file? I want to (import?link?) JSON objects to display them as location markers.
I want to know how to declare and iterate the javascript variable
locations.
For var(i=0;i< locations.length;i++){[
[json_data.user_name, json_data.point],
]
var map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(49.279504, -123.1162),
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var marker, i;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
icon: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}
})(marker, i));
}
Guide me if I went unnecessarily convoluted way to do a simple task.
TL;DR
No, what you are doing is not redundant and nothing get's written to the database from those answers.
You need to make a getJSON() or similar call to your API's endpoint to access the data.
You can do it on the 2nd step's call and declare it as a list.
What you are thinking is pretty much correct but there is room for improvement (thus the long answer below).
Answer:
Some time ago I read a very good initiation tutorial on building a GIS application with geodjango and google maps. Read it and it should give you a great jump start.
After you read that we will follow a somewhat different way which leaves more room to play around with your front-end (use react for example or whatever comes to mind).
The back-end:
Create a view to retrieve the information you want (user_name, location) as JSON, using the values() queryset method which returns a list of dictionaries.
Since we have to JSONify a list, we will use JsonResponse and we will mark it as unsafe:
from django.http import JsonResponse
def my_view(request):
resp = MyModel.objects.all().values('user_name', 'location')
return JsonResponse(list(resp), safe=False)
Add an endpoint to access that view on urls.py:
urlpatterns = [
...
url(r'^my_endpoint/$', my_view, name='my_endpoint'),
...
]
Now whenever we access the my_endpoint/ we will get a JSON representation of every object's user_name and location in our database which will look like this:
[
{user_name: a_user, location: [lat, lng]},
{user_name: another_user, location: [lat, lng]},
...
]
Moving to the front-end now:
Make a getJSON() or an ajax() or any other type of call to the API and in the same time create a marker list (close to what #MoshFeu suggests):
let map = new google.maps.Map(document.getElementById('map'), {
center: new google.maps.LatLng(49.279504, -123.1162),
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
let markers = [];
$.getJSON( "my_base_url/my_endpoint", function(data) {
$.each(data, function() {
markers.push(
new google.maps.Marker({
position: {
lat: data['location'][0],
lng: data['location'][1]
},
map: map,
icon: 'http://maps.google.com/mapfiles/ms/icons/blue-dot.png'
})
);
});
});
...
And we are pretty much done!
You don't need to make any special serialization to your data.
You can query the data from any type of front-end you can imagine which gives you designing freedom.
My use-case. I used django.contrib.gis (django.contrib.gis.db.models.PolygonField) and needed to replace default map with Google maps + change default map coordinates, zoom, etc.
TL;DR
I created a new app called gis_addons with custom template and widget to use.
I instructed my model admin (using formfield_overrides) to use my own map widget.
Make sure to add the gis_addons to INSTALLED_APPS.
File: gis_addons/templates/gis_addons/openlayers_googlemaps.html
{% extends "gis/openlayers.html" %}
{% load i18n l10n %}
{% block base_layer %}
var base_layer = new ol.layer.Tile({
source: new ol.source.XYZ({
attributions: [new ol.Attribution({ html: '' })],
maxZoom: 25,
url: "http://mt0.google.com/vt/lyrs=r&hl=en&x={x}&y={y}&z={z}&s=Ga"
})
});
{% endblock %}
{% block options %}var options = {
base_layer: base_layer,
geom_name: '{{ geom_type }}',
id: '{{ id }}',
map_id: '{{ id }}_map',
map_options: map_options,
map_srid: {{ map_srid|unlocalize }},
name: '{{ name }}',
default_lat: 53.2193835,
default_lon: 6.5665018,
default_zoom: 15
};
{% endblock %}
File: gis_addons/widgets.py
from django.contrib.gis.forms.widgets import OpenLayersWidget
class GoogleMapsOpenLayersWidget(OpenLayersWidget):
"""Google Maps OpenLayer widget."""
template_name = 'gis_addons/openlayers_googlemaps.html'
File: my_app/models.py
from django.db import models
from django.contrib.gis.db import models as gis_models
from django.utils.translation import ugettext_lazy as _
class MyModel(models.Model):
# ...
coordinates = gis_models.PolygonField(
verbose_name=_("Geo coordinates"),
)
def __str__(self):
return self.name
File: my_app/admin.py
from django.contrib import admin
from django.contrib.gis.db.models import PolygonField
from gis_addons.widgets import GoogleMapsOpenLayersWidget
from my_app.models import MyModel
#admin.register(MyModel)
class MyModelAdmin(admin.ModelAdmin):
# ...
formfield_overrides = {
PolygonField: {"widget": GoogleMapsOpenLayersWidget}
}

Using a Leaflet realtime layer in a markercluster group

I'm using Leaflet in combination with the realtime and markercluster plugins in order to show markers, that get live updated on a map.
The plugins work great independent from each other, but the problem arises when I want to cluster the realtime layer using the markercluster features.
Code sample for the realtime layer in which I convert the json to markers, asign a custom icon and apply some onEachFeature function:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
What I'm able to do with non-realtime marker layers is to create a markercluster group and add the layer to it, so the markers get clustered like this:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addLayer(someLayer);
However when I add the realtimeLayer to the clustergroup, the clustering is not applied, or the marker do net get loaded at all. What am I missing? Thanks!
You need to add the container option to your realtime object options.
From the official Leaflet Realtime documentation:
L.Realtime can also use other layer types to display the results, for
example it can use a MarkerClusterGroup from Leaflet MarkerCluster:
pass a LayerGroup (or any class that implements addLayer and
removeLayer) to L.Realtime's container option. (This feature was added
in version 2.1.0.)
https://github.com/perliedman/leaflet-realtime#overview
So after you initialize your cluster group and add it to map:
var clusterGroup = L.markerClusterGroup();
clusterGroup.addTo(map);
You can then pass the clusterGroup object to your realtime object in the container option:
realtimeLayer = L.realtime({
url: 'someURL',
crossOrigin: true,
type: 'json'
}, {
container: clusterGroup
interval: 3 * 1000,
onEachFeature: onEachFeature,
pointToLayer: function(feature, latlng) {
return L.marker(latlng, {
icon: customIcon
});
}
});
Now when you add the realtime object to the map, it should cluster correctly:
realtimeLayer.addTo(map)
The official Leaflet Realtime repo has an example for doing what you want with the added option of grouping multiple L.Realtime objects: https://github.com/perliedman/leaflet-realtime/blob/master/examples/earthquakes.js

Categories

Resources