Is there any idle event for mapbox gl js? - mapbox

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)
});
}

Related

Bound popup removed when layer changed in control

I have a map with a layer control that has overlays specified in the baselayer parameter:
var overlays = {
'Layer 1': mylayer1,
'Layer 2': mylayer2
};
L.control.layers( overlays, null, { collapsed: false } ).addTo( map );
I specify my layers as follows:
var mylayer1 = L.esri.featureLayer({
url: 'https://.../MapServer/5'
}).on( 'load', function ( e ) {
...
}).on( 'loading', function ( e ) {
...
}).bindPopup( function ( layer ) {
return L.Util.template( '<p>{_score}</p>', layer.feature.properties );
});
The issue is that when I change layers in the control the bindPopup event no longer gets called.
It's almost like the layer z-index is not updated. Would appreciate any insight on how I can address this.
See: https://codepen.io/jvanulde/pen/LYyOWZo
I see no one has given an answer.
A little around, but it works.
You add the id: x to each layer. Later in the loop you check which layer is active, and all the rest of the layers you add the style display: none.
window.addEventListener('DOMContentLoaded', () => {
let tiles = L.tileLayer('//{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors, Points &copy 2012 LINZ'
});
let l1 = L.esri.featureLayer({
url: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/nhsl_en/MapServer/1',
id: 0, // required
simplifyFactor: 0.25,
precision: 5,
fields: ['OBJECTID'],
renderer: L.canvas()
}).bindPopup(function(layer) {
return L.Util.template('<p>Layer 1: <strong>{OBJECTID}</strong></p>', layer.feature.properties);
});
let l2 = L.esri.featureLayer({
url: 'https://maps-cartes.services.geo.ca/server_serveur/rest/services/NRCan/nhsl_en/MapServer/2',
id: 1, // required
simplifyFactor: 0.25,
precision: 5,
fields: ['OBJECTID'],
renderer: L.canvas()
}).bindPopup(function(layer) {
return L.Util.template('<p>Layer 2: <strong>{OBJECTID}</strong></p>', layer.feature.properties);
});
let map = L.map('map', {
center: [49.2827, -123.1207],
zoom: 12,
layers: [tiles]
});
let overlays = {
'Layer 1': l1,
'Layer 2': l2
};
L.control.layers(overlays, null, {
collapsed: false
}).addTo(map);
l1.addTo(map);
map.on('baselayerchange', function(e) {
const layersCanvas = document.querySelectorAll('.leaflet-overlay-pane > canvas');
layersCanvas.forEach((layer, index) => {
layer.style.display = '';
if (index !== e.layer.options.id) {
layer.style.display = 'none';
}
});
});
});
html {
height: 100%;
}
body {
min-height: 100%;
margin: 0;
padding: 0;
}
#map {
width: 100%;
height: 100vh;
}
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"></script>
<script src="https://unpkg.com/esri-leaflet#3.0.2/dist/esri-leaflet.js"></script>
<div id="map"></div>

Not closing camera in zxing

In the Zxing library, I want to close the camera when the user clicks cancel. So I used a button and add onclick event to it. it is calling resetReader method. I called this method after gets a barcode value or in the cancel button onclick event.If it is getting barcode values, this resetReader method works perfectly. if we cancel, the camera doesn't stop. Am I missing something?
const codeReader = new BrowserMultiFormatReader(hints);
const resetReader = () => {
codeReader.reset();
codeReader.stopContinuousDecode();
};
for those who haven't figured it out yet? I have found a solution to this problem. Harendrra's solution didn't work for me, but this one did in combination with usestate. For my project the code uses Bootstrap. So when I click on a button the Modal appears. The camera loads. When I click on the Close button the camera disappears. Hope this is a solutions for everyone, enjoy ;-)
export default function Example(props) {
// codeReader
const [codeReader, setReader] = useState(new BrowserMultiFormatReader());
const [videoInputDevices, setVideoInputDevices] = useState([]);
const [selectedVideoDevice, selectVideoDevice] = useState('');
useEffect(() => {
(async () => {
const videoInputDeviceList = await codeReader.listVideoInputDevices();
setVideoInputDevices(videoInputDeviceList);
if (videoInputDeviceList.length > 0 && selectedVideoDevice == null) {
selectVideoDevice(videoInputDeviceList[0].deviceId);
}
})();
}, [codeReader, selectedVideoDevice]);
const handleShow = () => {
setBrand('');
// Open modal.
setShow(true);
codeReader.decodeFromVideoDevice(selectedVideoDevice, 'videoElement', (res) => {
setCanClose(true);
if (res) {
const rawText = res.getText();
axios
.get(`https://world.openfoodfacts.org/api/v0/product/${rawText}.json`)
.then((result) => {
// set data
setBrand(result.data.product.brands);
// close modal
setShow(false);
// codeReader reset
codeReader.reset();
})
.catch((err) => console.log('error', err));
}
});
};
const handleClose = () => {
// codeReader reset.
setReader(codeReader.reset());
// Close modal
setShow(false);
// Set new codeReader.
// The solution for the error messages after the codeReader reset.
// This will build the codeReader for the next time.
setReader(new BrowserMultiFormatReader(hints));
};
return (
<Fragment>
<div className='py-2'>
<div>Brand: {brand}</div>
<Button variant='primary' onClick={handleShow}>
Launch static backdrop modal
</Button>
<Modal show={show} onHide={handleClose} backdrop='static' keyboard={false} centered id='scanProductModal'>
<Modal.Body>
<div
onChange={(event) => {
const deviceId = event.target.value;
selectVideoDevice(deviceId);
}}
>
<div className='button-group-top'>
<select className='form-select form-select-sm' aria-label='Default select example'>
{videoInputDevices &&
videoInputDevices.map((inputDevice, index) => {
return (
<option value={inputDevice.deviceId} key={index}>
{inputDevice.label || inputDevice.deviceId}
</option>
);
})}
</select>
</div>
<video id='videoElement' width='600' height='400' />
<Button className='btn btn-danger' onClick={handleClose}>
Close
</Button>
</div>
</Modal.Body>
</Modal>
</Fragment>
);
}
Yes, I resolved. You have to create codeReader object at the top of the Class. Try this code.
import "../App.css";
import { BrowserBarcodeReader } from "#zxing/library";
class Barcode extends React.Component {
codeReader = new BrowserBarcodeReader();
constructor(props) {
super(props);
this.state = { reader: {}, selectedDevice: "" };
this.startButton = this.startButton.bind(this);
this.resetButton = this.resetButton.bind(this);
this.getBarcode = this.getBarcode.bind(this);
}
componentDidMount() {
this.getBarcode();
}
startButton() {
console.log("start", this.codeReader);
this.codeReader
.decodeOnceFromVideoDevice(this.state.selectedDevice, "video")
.then(result => {
document.getElementById("result").textContent = result.text;
})
.catch(err => {
console.error(err.toString());
document.getElementById("result").textContent = err;
});
console.log(
`Started continous decode from camera with id ${this.state.selectedDevice}`
);
}
resetButton() {
this.codeReader && this.codeReader.reset();
document.getElementById("result").textContent = "";
}
getBarcode() {
let selectedDeviceId;
return this.codeReader.getVideoInputDevices().then(videoInputDevices => {
const sourceSelect = document.getElementById("sourceSelect");
selectedDeviceId = videoInputDevices[0].deviceId;
if (videoInputDevices.length > 1) {
videoInputDevices.forEach(element => {
const sourceOption = document.createElement("option");
sourceOption.text = element.label;
sourceOption.value = element.deviceId;
sourceSelect.appendChild(sourceOption);
});
sourceSelect.onchange = () => {
selectedDeviceId = sourceSelect.value;
};
const sourceSelectPanel = document.getElementById(
"sourceSelectPanel"
);
sourceSelectPanel.style.display = "block";
}
this.setState({
selectedDevice: selectedDeviceId
});
})
.catch(err => {
alert(err);
});
}
render() {
return (
<div>
<h2>Barcode</h2>
{Object.keys(this.codeReader).length > 0 && (
<div>
<div>
<button
className="button"
id="startButton"
onClick={this.startButton}
>
Start
</button>
<button
className="button"
id="resetButton"
onClick={this.resetButton}
>
Reset
</button>
</div>
<div>
<video
id="video"
width="600"
height="400"
style={{ border: "1px solid gray" }}
></video>
</div>
<label>Result:</label>
<pre>
<code id="result"></code>
</pre>
</div>
)}
</div>
);
}
}
export default Barcode; ```

Is there a way to programme bingmap's infobox close button?

In the bingmaps documentation, you can add custom actions to the infobox. I would like to know if there's a similar way to program the default closeButton?
Ideally, I would like to be able to do something like this:
const infobox = new Microsoft.Maps.Infobox(selectedTipCoordinates, {
title: selectedTip.title,
description: selectedTip.description,
closeButton: () => console.log('hello')
});
Unfortunately close event handler could not be customized via InfoboxOptions object, so you could consider either to implement a custom HTML Infobox or override info window click handler. The following example demonstrates how to keep info window opened once close button is clicked and add a custom action:
Microsoft.Maps.Events.addHandler(infobox, 'click', handleClickInfoBox);
function handleClickInfoBox(e){
var isCloseAction = e.originalEvent.target.className == "infobox-close-img";
if(isCloseAction){
//keep info window open..
e.target.setOptions({visible: true});
//apply some custom actions..
console.log("Close button clicked");
}
}
function loadMapScenario() {
var map = new Microsoft.Maps.Map(document.getElementById("myMap"), {
center: new Microsoft.Maps.Location(47.60357, -122.32945)
});
var infobox = new Microsoft.Maps.Infobox(map.getCenter(), {
title: "Title",
description: "Description",
actions: [
{
label: "Handler1",
eventHandler: function() {
console.log("Handler1");
}
},
{
label: "Handler2",
eventHandler: function() {
console.log("Handler2");
}
},
{
label: "Handler3",
eventHandler: function() {
console.log("Handler3");
}
}
]
});
infobox.setMap(map);
Microsoft.Maps.Events.addHandler(infobox, 'click', handleClickInfoBox);
}
function handleClickInfoBox(e){
var isCloseAction = e.originalEvent.target.className == "infobox-close-img";
if(isCloseAction){
//keep info window open..
e.target.setOptions({visible: true});
//apply some custom actions..
console.log("Close button clicked");
}
}
body{
margin:0;
padding:0;
overflow:hidden;
}
<script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?key=&callback=loadMapScenario' async defer></script>
<div id='myMap' style='width: 100vw; height: 100vh;'></div>
No, I don't think there's a way to wire the behavior of default close button differently. That said, you can approximate the desired outcome with a little more work: creating a custom infobox with the same style and then you'll have 100% control:
e.g. (notice the onClick handler on the close button div):
var center = map.getCenter();
var infoboxTemplate = '<div class="Infobox" style=""><a class="infobox-close" href="javascript:void(0)" onClick="function test(){ alert(\'test!\'); } test(); return false;" style=""><img class="infobox-close-img" src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjE0cHgiIHdpZHRoPSIxNHB4IiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiPjxwYXRoIGQ9Ik03LDBDMy4xMzQsMCwwLDMuMTM0LDAsN2MwLDMuODY3LDMuMTM0LDcsNyw3YzMuODY3LDAsNy0zLjEzMyw3LTdDMTQsMy4xMzQsMTAuODY3LDAsNywweiBNMTAuNSw5LjVsLTEsMUw3LDhsLTIuNSwyLjVsLTEtMUw2LDdMMy41LDQuNWwxLTFMNyw2bDIuNS0yLjVsMSwxTDgsN0wxMC41LDkuNXoiLz48L3N2Zz4=" alt="close infobox"></a><div class="infobox-body" style="max-width: 256px; max-height: 126px; width: 125px;"><div class="infobox-title" >{title}</div><div class="infobox-info" style=""><div>{description}</div></div><div class="infobox-actions" style="display: none;"><ul class="infobox-actions-list"><div></div></ul></div></div><div class="infobox-stalk" style="top: 73.8px; left: 55.5px;"></div></div>';
var infobox = new Microsoft.Maps.Infobox(center, {
htmlContent: infoboxTemplate.replace('{title}', 'myTitle').replace('{description}', 'myDescription'),
offset: new Microsoft.Maps.Point(-64, 16)
});

changeRequest in Alloy 2.5 and Liferay 6.2 cannot be called

I am trying to migrate a portlet from Liferay 6.1 to 6.2 and forced to adapt the Alloy code to 2.5 version and the aui-pagination part:
pagination = new A.Pagination({
circular: false,
containers: '.pagination',
on: {
changeRequest: function(event) {
var newState = event.state;
this.setState(newState);
}
},
total: 10,
});
But whenever I call the changeRequest() of the pagination instance from other functions I get errors:
this._pagination.changeRequest();
Is there any solution for this?
Your question is a little strange. How would you call changeRequest() without passing an event in your example? And why set the state from the event when that's already happening automatically?
To answer the more generic question that you are asking, there are several potential solutions to calling the changeRequest() function programmatically:
Define a named function and set it to be the changeRequest() function:
function changeRequest() {
console.log('changeRequest function called!');
}
var pagination = new Y.Pagination({ /* ...your code here... */ });
pagination.on('changeRequest', changeRequest);
// OR if you don't need to access the pagination component
// in your changeRequest() method
new Y.Pagination({
/* ...your code here... */
on: {
changeRequest: changeRequest
}
});
This method will only work if you do not need to use the event parameter, or if you only use the event parameter when the actual event occurs, or if you construct the event parameter yourself.
Runnable example using your code:
YUI().use('aui-pagination', function(Y) {
var pagination = new Y.Pagination({
circular: false,
containers: '.pagination',
total: 10,
});
function changeRequest(event) {
if (event) {
alert('changeRequest called with event');
var newState = event.state;
pagination.setState(newState);
} else {
alert('changeRequest called without event');
}
}
pagination.after('changeRequest', changeRequest);
pagination.render();
Y.one('#button').on('click', function() {
changeRequest();
});
});
<script src="http://cdn.alloyui.com/2.0.0/aui/aui-min.js"></script>
<link href="http://cdn.alloyui.com/2.0.0/aui-css/css/bootstrap.min.css" rel="stylesheet"></link>
<br />
<button id="button">call <code>changeRequest()</code></button>
Call pagination.next() or pagination.prev():
YUI().use('aui-pagination', function(Y) {
// ...your code here...
pagination.next();
});
Runnable example using your code:
YUI().use('aui-pagination', function(Y) {
var pagination = new Y.Pagination({
circular: false,
containers: '.pagination',
total: 10,
on: {
changeRequest: function(event) {
alert('changeRequest called with event');
var newState = event.state;
pagination.setState(newState);
}
}
}).render();
Y.one('#button').on('click', function() {
pagination.next();
});
});
<script src="http://cdn.alloyui.com/2.0.0/aui/aui-min.js"></script>
<link href="http://cdn.alloyui.com/2.0.0/aui-css/css/bootstrap.min.css" rel="stylesheet"></link>
<br />
<button id="button">call <code>changeRequest()</code></button>
Simulate a click event on one of the pagination items:
YUI().use('aui-pagination', 'node-event-simulate', function(Y) {
// ...your code here...
pagination.getItem(1).simulate('click');
});
Runnable example using your code:
YUI().use('aui-pagination', 'node-event-simulate', function(Y) {
var pagination = new Y.Pagination({
circular: false,
containers: '.pagination',
total: 10,
on: {
changeRequest: function(event) {
alert('changeRequest called with event');
var newState = event.state;
pagination.setState(newState);
}
}
}).render();
Y.one('#button').on('click', function() {
pagination.getItem(1).simulate('click');
});
});
<script src="http://cdn.alloyui.com/2.0.0/aui/aui-min.js"></script>
<link href="http://cdn.alloyui.com/2.0.0/aui-css/css/bootstrap.min.css" rel="stylesheet"></link>
<br />
<button id="button">call <code>changeRequest()</code></button>

Google Maps v3 - hide/modify map markers in the DirectionsRenderer

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