I'm getting Unable to get gMarker from markersScope! (in angular maps: https://github.com/angular-ui/angular-google-maps/blob/master/src/coffee/directives/api/models/parent/windows-parent-model.coffee#L146) when trying to add infoWindows. The windows do display, but behave erratically when updated.
Each time the user clicks on a movie the infoWindows should update with information about that movie at that cinema marker. It sometimes works, sometimes the infoWindows disappear and sometimes the markers disappear as well. The only error I get is the one above.
Controller and view code:
var createCinemaMarkers = function(cinemas) {
$scope.cinemaMarkers = [];
$scope.cinemaWindows = [];
for (var i = 0; i < cinemas.length; i++) {
getMoviesForCinema(cinemas[i].venue_id);
var map_coords = {
id: cinemas[i].venue_id,
title: cinemas[i].title,
options: {
title: cinemas[i].title,
random: 'blah blah blah'
},
clickable: true,
latitude: cinemas[i].coords.lat,
longitude: cinemas[i].coords.lng,
icon: 'images/cinema_icons/cinema.png'
}
if (!cinemas[i].movieTitle) {
cinemas[i].movieTitle = '';
}
var parameters = {
movieTitle: cinemas[i].movieTitle,
movieTimes: cinemas[i].movieTimes,
stuff: 'from props'
}
var infoWindow = {
id: cinemas[i].venue_id,
coords: {
latitude: cinemas[i].coords.lat,
longitude: cinemas[i].coords.lng
},
options: {
title: "I AM TITLE"
},
show: true,
templateUrl: 'views/info-window.html',
templateParameter: parameters,
isIconVisibleOnClick: true,
closeClick: 'none'
}
$scope.cinemaWindows.push(infoWindow);
$scope.cinemaMarkers.push(map_coords);
};
};
<ui-gmap-google-map center="map.center" zoom="map.zoom" events="mapEvents">
<ui-gmap-markers models="cinemaMarkers" events="events" options="'options'" coords="'self'" icon="'icon'" fit="'true'" popover-placement="top" popover="On the Top!">
<ui-gmap-windows models="cinemaWindows" templateUrl="'templateUrl'" templateParameter="'templateParameter'" options="'options'">
</ui-gmap-windows>
</ui-gmap-markers>
</ui-gmap-google-map>
I had a similar problem where in the directive coords="'self'" but markers were set to coords: {latitude:xxxx,longitude:xxxxx}
Because your ui-gmap-markers is set to coords="'self'" so try remove coords in infoWindow:
var infoWindow = {
id: cinemas[i].venue_id,
latitude: cinemas[i].coords.lat,
longitude: cinemas[i].coords.lng,
options: {
title: "I AM TITLE"
},
show: true,
templateUrl: 'views/info-window.html',
templateParameter: parameters,
isIconVisibleOnClick: true,
closeClick: 'none'
}
Related
Hey vue-ers!
I am using vue2-google-maps with all its glories and so far I have managed a lot except for custom buttons within an info-window. So far I can click on a marker and it shows the related custom info-window with the right info. The only thing I am missing now is making those buttons work. For example the close button: I can click on it and it speaks to the component method but does not close it. The close button works the same as selecting the markers, but at the same time it's not? The values update to false, but not being updated in the maps, while I select a marker it updates like a charm. So I am quite stuck here and fairly confused, any help, ideas and tips are appreciated!
Here is my code for reference:
Template
<gmap-map
id="map"
:center="center"
:zoom=13
:options="{
disableDefaultUI: true,
zoomControl: true,
clickableIcons: true,
}">
<gmap-marker
v-for="(location, index) in locations"
:position="{lat: location.latitude, lng: location.longitude}"
:icon="location.icon"
:zone="location.zone"
:jettyNumber="location.jettyNumber"
:selected="location.selected"
:zIndex="location.zIndex"
#mouseover="mouseOverMarker(index)"
#mouseout="mouseOutMarker(index)"
#click="openInfoWindow(index)"
:label="{
text: location.jettyNumber.toString(),
color: '#fff',
fontSize: '13px',
fontFamily: 'din_round_otbold'
}">
<gmap-info-window
:opened="location.infoBoxOpen">
<div class="infoWindow" style="width: 300px;">
<div id="dock-zone" :class="getZoneClass(location.zone)">{{ getZoneClassText(location.zone) }}</div>
<h2 id="infoWindow-location">{{ location.name }}</h2>
<div id="close-btn" #click="closeInfoWindow(index)"></div>
<a class="btn btn-primary google-maps-infowindow-button">Kies als <b>{{ inputData.label }}</b></a>
<span></span>
</div>
</gmap-info-window>
</gmap-marker>
</gmap-map>
Component Script
import $ from "jquery";
export default {
data: function(){
return {
icons: {
stopInner: {
icon: process.env.VUE_APP_PUBLIC_URL + '/Assets/images/pinpoint_on_map_inner.svg'
},
stopOuter: {
icon: process.env.VUE_APP_PUBLIC_URL + '/Assets/images/pinpoint_on_map_outer.svg'
},
stopOutside: {
icon: process.env.VUE_APP_PUBLIC_URL + '/Assets/images/pinpoint_on_map_outside.svg'
},
stopSelected: {
icon: process.env.VUE_APP_PUBLIC_URL + '/Assets/images/pinpoint_on_map_active.svg'
}
},
locations: [],
center: {lat: 51.9004, lng: 4.46849},
inputData: {}
};
},
methods: {
initMap(locations, inputData) {
// Set maps specific data
for(var i = 0; i < locations.length; i++) {
locations[i].selected = false;
locations[i].infoBoxOpen = false;
locations[i].zIndex = locations[i].jettyNumber;
locations[i].icon = this.getIcon(locations[i].zone);
}
this.inputData = inputData;
this.locations = locations;
},
getIcon(zone) {
switch(zone){
case "centre":
return this.icons.stopInner.icon;
break;
case null:
return this.icons.stopOutside.icon;
break;
default:
return this.icons.stopOuter.icon;
break;
}
},
getZoneClass(zone) {
switch(zone){
case "centre":
return "centrum";
break;
case null:
return "buiten";
break;
default:
return "";
break;
}
},
getZoneClassText(zone) {
if(zone){
return zone;
}else{
return "outside";
}
},
// TODO: Not really setting the zindex, need to dig deeper
mouseOverMarker(locationIndex) {
this.locations[locationIndex].zIndex = 99998;
},
mouseOutMarker(locationIndex) {
this.locations[locationIndex].zIndex = this.locations[locationIndex].jettyNumber;
},
openInfoWindow(location){
this.center = {lat: location.latitude, lng: location.longitude};
this.setSelectedLocation(location);
},
setSelectedLocation(selectedLocationIndex){
this.unselectLocations();
// Set selected
this.locations[selectedLocationIndex].zIndex = 88888;
this.locations[selectedLocationIndex].icon = this.icons.stopSelected.icon;
this.locations[selectedLocationIndex].selected = true;
this.locations[selectedLocationIndex].infoBoxOpen = true;
this.center = {
lat: this.locations[selectedLocationIndex].latitude,
lng: this.locations[selectedLocationIndex].longitude
};
this.alterDefaultInfoWindowStyle();
},
unselectLocations() {
for(var i = 0; i < this.locations.length; i++) {
this.locations[i].icon = this.getIcon(this.locations[i].zone);
this.locations[i].zIndex = this.locations[i].jettyNumber;
this.locations[i].selected = false;
this.locations[i].infoBoxOpen = false;
}
},
alterDefaultInfoWindowStyle() {
// TODO: a very nasty fix, need a better way to handle this
setTimeout(function(){
var iwOuter = $('.gm-style-iw');
iwOuter.parent().parent().css({ top: '20px' });
iwOuter.css({ top: '0px' });
iwOuter.css({ left: '26px' });
var iwBackground = iwOuter.prev();
iwBackground.css({ 'display': 'none' });
var iwCloseBtn = iwOuter.next();
iwCloseBtn.hide();
iwOuter.children().eq(0).css({ overflow: 'visible' });
}, 10);
},
closeInfoWindow(selectedLocationIndex) {
this.unselectLocations();
},
closeMaps() {
this.$emit('close-maps')
}
}
}
Since the appearance of info window is determined by locations[index].infoBoxOpen the standard close handler (#closeclick) needs to be implemented as well, like this:
<gmap-info-window
:opened="location.infoBoxOpen"
#closeclick="location.infoBoxOpen=false">
...
</gmap-info-window>
I would also propose to modify the way how info window is created. Instead of creating info window per marker, to create only a single instance of info window. In addition to performance benefits it would make it more clear to manage info window state, for example:
<gmap-map :center="center" :zoom="zoom" ref="map">
<gmap-marker
:key="index"
v-for="(location,index) in locations"
:position="{lat: location.lat,lng:location.lng}"
:clickable="true"
#click="openInfoWindow(location)"
/>
<gmap-info-window v-if="selectedLocation !== null" :position="{lat: selectedLocation.lat,lng:selectedLocation.lng}" :opened="infoBoxOpen" #closeclick="closeInfoWindow()">
<div class="infoWindow">
<h2 id="infoWindow-location">{{ selectedLocation.name }}</h2>
<button #click="closeInfoWindow()">Close</button>
</div>
</gmap-info-window>
</gmap-map>
export default {
data: () => ({
zoom: 5,
center: { lat: 59.339025, lng: 18.065818 },
selectedLocation: null,
infoBoxOpen: false,
locations: [
{
Id: 1,
name: "Oslo",
lat: 59.923043,
lng: 10.752839
},
{
Id: 2,
name: "Stockholm",
lat: 59.339025,
lng: 18.065818
},
{
Id: 3,
name: "Copenhagen",
lat: 55.675507,
lng: 12.574227
},
{
Id: 4,
name: "Berlin",
lat: 52.521248,
lng: 13.399038
},
{
Id: 5,
name: "Paris",
lat: 48.856127,
lng: 2.346525
}
]
}),
methods: {
openInfoWindow(location) {
this.selectedLocation = location
this.infoBoxOpen = true;
},
closeInfoWindow() {
this.infoBoxOpen = false;
}
}
};
Here is a demo that demonstrates how to manage info window per multiple markers
I'm trying to add cities on a county map. The lat and long are drawn corectcly on the full size map(Romania level) but on the county map these are drawn wrong. I think I should rescale the map or lat/long of the city, I don't know...
How should I generate the county map in accordance with cities lat/long?
The code is listed below:
http://jsfiddle.net/xzAx7/33/
var map;
AmCharts.ready(function() {
map = new AmCharts.AmMap();
map.pathToImages = "http://www.ammap.com/lib/images/";
//map.panEventsEnabled = true; // this line enables pinch-zooming and dragging on touch devices
map.balloon.color = "#000000";
var wordlDataProvider = {
mapVar: AmCharts.maps.Cluj,
getAreasFromMap: true,
areas: [
{ id: "FR", color: "#4444ff" },
{ id: "RU", color: "#4444ff" },
{ id: "US", color: "#4444ff" }
],
images: [{
title: "ClujNapoca",
latitude: 46.85307355,
longitude: 23.63327696,
type: "circle",
color: "red",
scale: 0.5
}, {
title: "Turda",
latitude: 46.5745618,
longitude: 23.78573862,
type: "circle",
color: "red",
scale: 0.5
}]
};
map.dataProvider = wordlDataProvider;
map.areasSettings = {
autoZoom: true,
selectedColor: "#CC0000"
};
map.write("mapdiv");
});
I've found the solution. You need to define "defs" properties (leftLongiitude, ...) when you create a custom map. This is specified in this article - https://www.amcharts.com/tutorials/creating-custom-maps-for-javascript-ammap/
In the amCharts article is explained how you can get these "defs" properties.
I've changes the code below to understand how it works
"defs": {
"amcharts:ammap": {
"projection":"mercator",
"leftLongitude":"22.607117",
"topLatitude":"47.363798",
"rightLongitude":"24.261932",
"bottomLatitude":"46.384241"
}
}
demo: http://jsfiddle.net/xzAx7/35/
I am using Angular and leaflet and want to build a map with different markers, eg.: ships and bridges. I want to update them individually without removing and setting all markers again. So when I have new ships, I just want to call the ship markers, update them and the bridge markers stay the same.
Right now, I tried something like this:
angular.module('angularMapApp')
.controller('MainCtrl', ['$scope', 'RequestService', 'setShipMarkers', '$q', function($scope, RequestService, setShipMarkers, $q) {
angular.extend($scope, {
hamburg: {
lat: 53.551086,
lng: 9.993682,
zoom: 13
},
markers: {
ships: {
m1: {
lat: 42.20133,
lng: 2.19110
},
m2: {
lat: 42.21133,
lng: 2.18110
}
},
bridges: {
m3: {
lat: 42.19133,
lng: 2.18110
},
m4: {
lat: 42.3,
lng: 2.16110
}
}
},
defaults: {
tileLayer: 'http://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png',
zoomControlPosition: 'topright',
tileLayerOptions: {
opacity: 0.9,
detectRetina: true,
reuseTiles: true,
},
scrollWheelZoom: false
}
});
But this does not works, as I get the following error (after setting markers-nested: true in my view):
You must add layers to the directive if the markers are going to use
this functionality.
However why do I need layers, if I just want to call different markers group on the same layer. I just do not want to update all of them at once.
So maybe someone can tell me, how to get separate marker groups and how to call them to update them.
For each kind of nested marker you have to create its own group layer like this, they can be empty:
layers: {
overlays: {
ships: { // use the same name as in the marker object
name: "Ships",
type: "group",
visible: true
},
bridges: { // use the same name as in the marker object
name: "bridges",
type: "group",
visible: true
}
}
}
By doing that you will also have to move the OSM base layer into the layers.baselayers object, but markers-nested="true" works this way.
Demo: http://plnkr.co/edit/HQx8bQmmsFUGcLxYt95N?p=preview
Well, i'm using angular-google-maps, always receiving this error message, now i cleaned all my code and just put a simple example from the lib git, still the same error message.
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options">
<ui-gmap-marker idkey="marker.id" coords="marker.coords" options="marker.options" events="marker.events"></ui-gmap-marker>
</ui-gmap-google-map>
JS:
$scope.map = {center: {latitude: 40.1451, longitude: -99.6680 }, zoom: 4 };
$scope.options = {scrollwheel: false};
$scope.coordsUpdates = 0;
$scope.dynamicMoveCtr = 0;
$scope.marker = {
id: 1,
coords: {
latitude: 40.1451,
longitude: -99.6680
},
options: { draggable: true },
events: {
dragend: function (marker, eventName, args) {
var lat = marker.getPosition().lat();
var lon = marker.getPosition().lng();
$scope.marker.options = {
draggable: true,
labelContent: "lat: " + $scope.marker.coords.latitude + ' ' + 'lon: ' + $scope.marker.coords.longitude,
labelAnchor: "100 0",
labelClass: "marker-labels"
};
}
}
};
Console error log image
Already tried the version from the package.json from the project, etc, and nothing seems to change.
Using the npm last version of angular-google-maps, specific 2.2.1, give the error mentioned.
i solved changing from :
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-google-maps/2.2.1/angular-google-maps.min.js"></script>
to :
<script src="http://rawgit.com/angular-ui/angular-google-maps/2.0.X/dist/angular-google-maps.js"></script>
My Angular version is v1.4.7.
Currently, I am displaying 500-600 Markers on Google map, with their names as tooltip. Now,
I need to display the tool-tip of all overlapping markers as comma-separated i.e. Marker1, Marker2, Marker3 etc. if Marker1, Marker2, Marker3 are overlapped on map.
I found many other different examples on google map at internet especially at GeoCodeZip, but not of my requirement.
if this requirement is once filled, Am afraid of performance issues on zoom changed events, as tooltip needed to be updated (if overlapping is changed).
Update1 : I have already show Overlapping Marker spiderfier to client but not acceptable.
Does anyone have right path or working example ?
Thanks
-Anil
The core of this is to find the pixel distance between LatLngs. Then before adding each marker check the pixel distance between it and any existing markers. If there is another marker nearby add to the title otherwise create a new marker. jsFiddle
function init() {
var mapOptions = {
center: new google.maps.LatLng(0, -0),
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map-canvas'),mapOptions);
// to get the pixel position from the latlng
// https://stackoverflow.com/questions/1538681/how-to-call-fromlatlngtodivpixel-in-google-maps-api-v3
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
google.maps.event.addListenerOnce(map, 'idle', function() {
if (overlay.getProjection()) {
var points = [
{ latlng: new google.maps.LatLng(40, -100), title: '1' },
{ latlng: new google.maps.LatLng(40.125, -100.125), title: '2' },
{ latlng: new google.maps.LatLng(40.25, -100.25), title: '3' },
{ latlng: new google.maps.LatLng(40.5, -100.5), title: '4' },
{ latlng: new google.maps.LatLng(40.75, -100.75), title: '5' },
{ latlng: new google.maps.LatLng(41, -101), title: '6' },
{ latlng: new google.maps.LatLng(35, -95), title: '7' },
{ latlng: new google.maps.LatLng(45, 105), title: '8' },
{ latlng: new google.maps.LatLng(25, -115), title: '9' },
{ latlng: new google.maps.LatLng(55, -85), title: '10' },
{ latlng: new google.maps.LatLng(30, -34), title: '11' }
];
// for each point
var markers = [];
points.forEach(function (point) {
var nearby = false;
var pointPixelPosition = overlay.getProjection().fromLatLngToContainerPixel(point.latlng);
markers.forEach(function(marker) {
var markerPixelPosition = overlay.getProjection().fromLatLngToContainerPixel(marker.getPosition());
// check for marker 'near by'
if (Math.abs(pointPixelPosition.x - markerPixelPosition.x) < 10 || Math.abs(pointPixelPosition.y - markerPixelPosition.y) < 10) {
nearby = true;
marker.setTitle(marker.getTitle() + ', ' + point.title);
}
});
// create new marker
if (!nearby) {
markers.push(new google.maps.Marker({ map: map, position: point.latlng, title: point.title }));
}
});
}
map.setCenter(new google.maps.LatLng(39.8282, -98.5795));
});
}