I'm using Google Maps v3.
I've already suppressed markers to display my own on the map itself.
I want to modify the ones displayed in the directions div but the images have no IDs or Classes
<img jsvalues=".src:markerIconPaths[$waypointIndex]" jstcache="13" src="http://maps.gstatic.com/intl/en_us/mapfiles/icon_greenA.png">
Is there some other way to modify the source, or do I need to roll my own directions renderer?
I was also having an issue with the markers in the directions output. There was no way to replace the markers without some extremely cumbersome js, which then had to include workarounds for the turn-by-turn directions, etc.
A simple way to do it is by css:
The A line is a table:
<table id="adp-placemark" class="adp-placemark" jstcache="0">
and B line is:
<table class="adp-placemark" jstcache="0">
So the following css will change the markers:
#adp-placemark img, .adp-placemark img {
display:none;
}
#adp-placemark {
font-weight: bold;
padding: 10px 10px 10px 30px;
background: white url(../images/map_icons/number_1.png) no-repeat left center;
}
.adp-placemark {
font-weight: bold;
padding: 10px 10px 10px 30px;
background: white url(../images/map_icons/number_2.png) no-repeat left center;
}
I also had a problem with access to marker "inside" directions render and didn't find any solution that would be good enough for me... So I made it by myself and created a little JavaScript class. I hope it will be helpful.
It uses only API documented methods and properties.
I'm looking forward for any comments and code improvements.
My code at: http://jsfiddle.net/mzwjW/6/
Edit: Just copied the whole JavaScript code here.
var map;
var custom;
var myOptions = {
zoom: 6,
center: new google.maps.LatLng(52.87916, 18.32910),
mapTypeId: 'terrain'
};
var markers = [];
$(function() {
map = new google.maps.Map($('#map')[0], myOptions);
custom = new customDirectionsRenderer(new google.maps.LatLng(50.87916, 16.32910), new google.maps.LatLng(52.87916, 16.32910), map);
//you have access to marker :)
custom.startMarker.setTitle('POLAND!!');
});
function customDirectionsRenderer(startPoint, endPoint, map) {
//!!!!! reference to our class
var that = this;
this.directionsDisplay = new google.maps.DirectionsRenderer({
draggable: true,
suppressMarkers: true,
map: map
});
google.maps.event.addListener(this.directionsDisplay, 'directions_changed', function () {
checkWaypoints();
});
this.directionsService = new google.maps.DirectionsService();
var draggedMarker;
var waypointsMarkers = new Array();
this.map = map;
this.polyline = '';
this.polylinePoints = [];
//<-- create Start and Stop Markers
this.startMarker = new google.maps.Marker({
position: startPoint,
title: 'Start',
map: map,
draggable: true,
optimized: false
});
this.endMarker = new google.maps.Marker({
position: endPoint,
title: 'End',
map: map,
draggable: true,
optimized: false
});
//-->
//<-- add events listeners to Start/Stop Markers
google.maps.event.addListener(this.startMarker, 'dragend', dragEnd);
google.maps.event.addListener(this.startMarker, 'dragstart', dragStart);
google.maps.event.addListener(this.startMarker, 'drag', drag);
google.maps.event.addListener(this.endMarker, 'dragend', dragEnd);
google.maps.event.addListener(this.endMarker, 'dragstart', dragStart);
google.maps.event.addListener(this.endMarker, 'drag', drag);
//-->
//<-- update directionsRenderer true - snap markers to nearest streets
update(true);
//-->
//<--privates
////<-- event handlers
function dragStart() {
draggedMarker = this;
}
function dragEnd() {
clearTimeout(this.timeout);
update(true);
}
function drag() {
if (this.timeout !== undefined) {
return;
}
this.timeout = setTimeout(function () { update(false); }, 200);
}
////-->
////<-- create draggable markers for Waypoints from given array of latlng objects
function createWaypointsMarkers(wpoints) {
$.each(waypointsMarkers, function (idx, obj) {
obj.setMap(null);
});
waypointsMarkers = [];
$.each(wpoints, function (idx, obj) {
var marker = new google.maps.Marker({
position: obj,
map: that.map,
draggable: true,
optimized: false,
title: idx.toString()
});
waypointsMarkers.push(marker);
google.maps.event.addListener(marker, 'dragend', dragEnd);
google.maps.event.addListener(marker, 'dragstart', dragStart);
google.maps.event.addListener(marker, 'drag', drag);
});
}
////-->
////--> check if new waypoint was created
function checkWaypoints() {
if (that.directionsDisplay.getDirections() !== undefined) {
if (waypointsMarkers.length !=
that.directionsDisplay.getDirections().routes[0].legs[0].via_waypoints.length) {
createWaypointsMarkers(that.directionsDisplay.getDirections().routes[0].legs[0].via_waypoints);
}
}
}
////-->
////--> Update directionsRenderer when move or drop marker
////bool setMarkersPositions - snap markers to nearest streets?
function update(setMarkersPositions) {
if (draggedMarker !== undefined) {
draggedMarker.timeout = undefined;
}
that.directionsDisplay.preserveViewport = true;
checkWaypoints();
var waypoints = [];
$.each(waypointsMarkers, function (idx, obj) {
waypoints.push({ location: obj.getPosition(), stopover: false });
});
var request = {
origin: that.startMarker.getPosition(),
destination: that.endMarker.getPosition(),
waypoints: waypoints,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
that.directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
that.directionsDisplay.setDirections(response);
if (waypointsMarkers.length != response.routes[0].legs[0].via_waypoints.length) {
createWaypointsMarkers(response.routes[0].legs[0].via_waypoints);
}
if (setMarkersPositions) {
that.startMarker.setPosition(response.routes[0].legs[0].start_location);
that.endMarker.setPosition(response.routes[0].legs[0].end_location);
$.each(response.routes[0].legs[0].via_waypoints, function (idx, obj) {
waypointsMarkers[idx].setPosition(obj);
});
that.polyline = response.routes[0].overview_polyline.points;
that.polylinePoints = response.routes[0].overview_path;
}
}
});
}
////-->
//-->
}
customDirectionsRenderer.prototype = new google.maps.MVCObject();
YES !
very nice with css
#adp-placemark img,.adp-placemark img{display:none}
#adp-placemark{height:31px;background:#fff url(../img/marker_start.png) no-repeat left center}
#adp-placemark .adp-text,.adp-placemark .adp-text{height:31px;font-weight: bold;padding-left:29px}
.adp-placemark{background:#fff url(../img/marker_end.png) no-repeat left center}
with marker_start.png and marker_end.png 19px * 31px
I don't know ther is no solution in google map api v3
any way you also can manage this with jQuery too
Related
I need some sort of google maps "idle" event for mapbox gl.
When every event fired and the map stop zoomin/out drag etc. and every layer has loaded, and the map is idle.
I have to use this code
map.on("render", function(e) {
if(map.loaded() && triggerOnce === true) {
//fires on zoomin runing
triggerOnce = false;
console.log("Render end")
setTimeout(somefunc(),1000)
}
})
Yes, as of mapbox-gl-js v0.52.0 there is now an idle event you can use. According to the docs:
Fired after the last frame rendered before the map enters an "idle"
state:
No camera transitions are in progress
All currently requested tiles have loaded
All fade/transition animations have completed
To use it:
map.once('idle', (e) => {
// do things the first time the map idles
});
map.on('idle', (e) => {
// do things every time the map idles
});
Demo: http://jsfiddle.net/godoshian/yrf0b9xt/
// Data from http://geojson.xyz/
const geojsonSource = 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_populated_places.geojson';
const outputContainer = document.getElementById('output-container');
mapboxgl.accessToken = 'pk.eyJ1IjoiY2NoYW5nc2EiLCJhIjoiY2lqeXU3dGo1MjY1ZXZibHp5cHF2a3Q1ZyJ9.8q-mw77HsgkdqrUHdi-XUg';
function createMap(container, layer = null) {
const map = new mapboxgl.Map({
container,
style: 'mapbox://styles/mapbox/light-v9',
});
map.on('idle', () => {
outputContainer.innerHTML += `${container} idle<br>`;
});
if (layer) {
map.on('load', () => {
map.addLayer(layer);
});
}
return map;
}
const map = createMap('map1');
setTimeout(() => {
fetch(geojsonSource)
.then(response => {
if (response.ok) return response.json();
throw Error(response);
})
.then(json => {
let layer = {
id: 'populated-places',
source: {
type: 'geojson',
data: json,
},
type: 'circle',
}
map.addLayer(layer);
createMap('map2', layer);
})
.catch(error => {
console.log(error);
})
}, 5000);
#demo {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
#demo #output-container {
flex: 1;
}
#demo .map {
height: 300px;
flex: 2;
}
<script src='https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.js'></script>
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v0.52.0/mapbox-gl.css' rel='stylesheet' />
<div id="demo">
<div id="output-container">
</div>
<div id="map1" class="map">
</div>
<div id="map2" class="map">
</div>
</div>
Relevant PR: https://github.com/mapbox/mapbox-gl-js/pull/7625
Docs: https://www.mapbox.com/mapbox-gl-js/api/#map.event:idle
just listen to moveend event, it will be fired after any moves on the map like dragging, zooming, rotating and pitching.
idle, not working, because it fire event every 1 second, continues trigger event.
map.on('idle', (e) => {
use moveend event instead.
map.on('moveend', (e) => {
You can have similar event by using setTimeout to monitor the onViewPortChange event
var changingViewPortTimeout;
onViewportChange(viewport) {
if (changingViewPortTimeout) {
clearTimeout(changingViewPortTimeout);
}
changingViewPortTimeout = setTimeout(function () {
onIdle(viewport);
}, 200)
});
}
I have a custom set of icons I'm setting various pins too. When the mouse hovers over them I'd like to bring them to the front and change the style to a different icon.
I use this code to create the pin. OnHover I see the new push pin and on mouseout it returns to how it was. However, it has transparent areas and I can see parts of the non-hover pushpin below it when hovering.
For bringing it to the forefront have tried changing the zIndex value and as far as I can tell it does nothing.
Do I need to refresh the map or something?
Feels like there is something I'm missing.
function createImagePin(location, obj)
{
var smallPin = getSmallPin(obj);
var pin = new Microsoft.Maps.Pushpin(location, {
icon: smallPin.data,
visible: true,
anchor: new Microsoft.Maps.Point(smallPin.width / 2, smallPin.height / 2) //Align center of pushpin with location.
});
pin.dataTarget = obj;
Microsoft.Maps.Events.addHandler(pin, 'mouseover', function (e)
{
if(e.targetType === 'pushpin')
{
var largePin = getLargePin(e.target.dataTarget);
e.target.setOptions({ icon: largePin.data, anchor: new Microsoft.Maps.Point(largePin.width/2,largePin.height/2) });
}
});
Microsoft.Maps.Events.addHandler(pin, 'mouseout', function (e)
{
if (e.targetType === 'pushpin')
{
var smallPin = getSmallPin(e.target.dataTarget);
e.target.setOptions({ icon: smallPin.data, anchor: new Microsoft.Maps.Point(smallPin.width/2,smallPin.height/2) });
}
});
return pin;
}
Currently shapes do no support zIndexing due to performance issues, but there are plans to add support for this. You can however use two layers for your data, the first to store your main data, and the second to display the hovered data. Below is a code sample that demonstrates hovering a pushpin, changing its style and displaying it above all other shapes on the map. When you mouse out the style goes back to what it was and the pushpin goes back to the main layer.
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=GetMap' async defer></script>
<script type='text/javascript'>
var map;
var defaultColor = 'blue';
var hoverColor = 'red';
var mouseDownColor = 'purple';
function GetMap()
{
map = new Microsoft.Maps.Map('#myMap', {
credentials: 'YourBingMapsKey'
});
var layer = new Microsoft.Maps.Layer();
map.layers.insert(layer);
var hoverLayer = new Microsoft.Maps.Layer();
map.layers.insert(hoverLayer);
//Add some random pushpins to fill the map and cover our hoverable main pushpin.
var pushpins = Microsoft.Maps.TestDataGenerator.getPushpins(300, map.getBounds());
layer.add(pushpins);
//Create our hoverable pushpin.
var pin = new Microsoft.Maps.Pushpin(map.getCenter(), {
color: defaultColor
});
layer.add(pin);
Microsoft.Maps.Events.addHandler(pin, 'mouseover', function (e) {
e.target.setOptions({ color: hoverColor });
//Move pin to hover layer.
layer.remove(pin);
hoverLayer.add(pin);
});
Microsoft.Maps.Events.addHandler(pin, 'mousedown', function (e) {
e.target.setOptions({ color: mouseDownColor });
});
Microsoft.Maps.Events.addHandler(pin, 'mouseout', function (e) {
e.target.setOptions({ color: defaultColor });
//Move pin to main layer.
hoverLayer.remove(pin);
layer.add(pin);
});
}
</script>
</head>
<body>
<div id="myMap" style="position:relative;width:600px;height:400px;"></div>
</body>
</html>
You can try this code sample out here: http://bingmapsv8samples.azurewebsites.net/#Pushpin_HoverStyle
I'm implementing google map into my ionic app, and I have a script in my index.html, which, will only allow the map works in the index.html.
But I need my map in my templates file route.html instead, so I believe I should move the script in the index.html to the specific controller.js file, but things here are written in $scope style, can anyone tell me how could I wrote the style into $scope style?
And why actually things won't works in the route.html as the same code is used?
<div id="map"></div>
Here's my script in my index.html:
<script>
function initMap() {
var uluru = {lat: -25.363, lng: 131.044};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: uluru
});
var marker = new google.maps.Marker({
position: uluru,
map: map
});
}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=APIKEY&callback=initMap">
</script>
And my controller in the controller.js
.controller('RouteCtrl', function($scope, $ionicLoading) {
$scope.mapCreated = function(map) {
$scope.map = map;
};
$scope.centerOnMe = function () {
console.log("Centering");
if (!$scope.map) {
return;
}
$scope.loading = $ionicLoading.show({
content: 'Getting current location...',
showBackdrop: false
});
navigator.geolocation.getCurrentPosition(function (pos) {
console.log('Got pos', pos);
$scope.map.setCenter(new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude));
$scope.loading.hide();
}, function (error) {
alert('Unable to get location: ' + error.message);
});
}
})
There 2 ways to solve your problem :
Change your script to angular method in controller or create a service , like:
var marker = new google.maps.Marker({
map: $scope.map,
animation: google.maps.Animation.DROP,
position: latLng
});
var infoWindow = new google.maps.InfoWindow({
content: "Here I am!"
});
google.maps.event.addListener(marker, 'click', function () {
infoWindow.open($scope.map, marker);
});
Change it to jquery in controller, but it not recommend because it will break to purpose of angular usage in ionic:
var map = new google.maps.Map($("#map"), {
zoom: 4,
center: uluru
});
I have list of markers that want to render in the map, but I want it one by one. In first click I want to make new marker. Then when I click to another location, I want my marker to just move to the new latLng not to create another marker. Here is my code:
function (licon, coord, data) {
var self = jQuery(this);
var map = self.data("map");
var latlng = new L.LatLng(coord[0], coord[1]);
//Create Marker
if (licon) {
var leafIcon = L.icon(licon);
console.log(typeof (marker));
if (typeof (marker) === 'undefined') {
var marker = L.marker(latlng, {
icon: leafIcon,
"markerData": data,
draggable: true
});
} else {
console.log('not undefined');
map.removeLayer(marker);
marker = L.marker(latlng, {
icon: leafIcon,
"markerData": data,
draggable: true
});
}
} else {
var marker = L.marker(latlng, {
"markerData": data,
draggable: true
});
}
marker.addTo(map);
return marker;
}
A quick example of the result: http://jsfiddle.net/ve2huzxw/43/
var currentMarker;
map.on("click", function (event) {
if (currentMarker) {
currentMarker.setLatLng(event.latlng);
return;
}
currentMarker = L.marker(event.latlng, {
draggable: true
}).addTo(map).on("click", function () {
event.originalEvent.stopPropagation();
});
});
document.getElementById("done").addEventListener("click", function () {
currentMarker = null;
});
You can also add a smooth transition to show the marker moving to the new position:
if (currentMarker) {
currentMarker._icon.style.transition = "transform 0.3s ease-out";
currentMarker._shadow.style.transition = "transform 0.3s ease-out";
currentMarker.setLatLng(event.latlng);
setTimeout(function () {
currentMarker._icon.style.transition = null;
currentMarker._shadow.style.transition = null;
}, 300);
return;
}
a slightly more consolidated solution some years later.
var currentMarker;
map2.on('click', function(e) {
if (currentMarker){
currentMarker.setLatLng(e.latlng)
} else {
currentMarker = new L.marker(e.latlng).addTo(map2);
};
//console.log('lat, lon: ', e.latlng.lat, e.latlng.lng);
});
leaflet now defaults to smoothly dragging the point over to the new coords.
I am creating an iPhone application in which i need to fetch the latitude longitude from gps.Now i am calling update-location delegate method and adding new location to the array after that i need to show all latitude longitude(locations ) on goggle map and the route between all locations.
Please help me out in showing the route.
Thanks in advance
Here is how you might do it with the GoogleMaps javascript api.
<style>
#map_canvas {
height: 190px;
width: 300px;
margin-top: 0.6em;
}
</style>
<script src="https://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
<div id="map_canvas" ></div>
<script language="javascript" type="text/javascript">
var latitude = 44.056389;
var longitude = -121.308056;
function initialize() {
var mapOptions = {
center: new google.maps.LatLng(latitude,longitude),
zoom: 9,
streetViewControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
// Create a draggable marker which will later on be binded to a
// Circle overlay.
var marker = new google.maps.Marker({
map: map,
position: new google.maps.LatLng(latitude,longitude),
draggable: true
});
// Add a Circle overlay to the map.
var circle = new google.maps.Circle({
strokeColor: "#0000FF",
strokeOpacity: 0.4,
strokeWeight: 2,
fillColor: "#0000FF",
fillOpacity: 0.20,
map: map,
radius: 16000 // meters
});
circle.bindTo('center', marker, 'position');
google.maps.event.addListener(marker, 'dragend', function() {
var location = marker.getPosition();
latitude = location.lat();
longitude = location.lng();
});
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
var location = place.geometry.location;
map.setCenter(location);
map.setZoom(9); // Why 9? Because it looks good.
marker.setPosition(location);
latitude = location.lat();
longitude = location.lng();
});
}
</script>