I am using Leaflet Map with geocoder (ESRI) and Routing Machine.
I have added two markers, let's say my home and my work
var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map)
.bindPopup("work").openPopup();
var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map)
.bindPopup("home").openPopup();
Here is an example fiddle:
https://jsfiddle.net/21nmk8so/1/
How can I add this markers/point as a predefined places for ControlGeocoder?
I want to use them in search and use as a start point / end point for route calculation.
Another example for the same question: how to add custom-fake city with lat/lon and be able to search (find route) to/from that city.
I don't know if this is the best solution but it is working:
Create a custom Geocoder Class which overwrites the geocode function. There you can overwrite the result function and apply suggestions to the result.
L.CustomGeocoder = L.Control.Geocoder.Nominatim.extend({
suggestions: [],
setSuggestions(arr){
this.suggestions = arr;
},
createSuggestionFromMarker(marker){
this.suggestions.push({name: marker.options.title, center: marker.getLatLng()});
},
getResultsOfSuggestions(query){
var results = [];
this.suggestions.forEach((point)=>{
if(point.name.indexOf(query) > -1){
point.center = L.latLng(point.center);
point.bbox = point.center.toBounds(100);
results.push(point);
}
});
return results;
},
geocode(query, resultFnc, context) {
var that = this;
var callback = function(results){
var sugg = that.getResultsOfSuggestions(query);
resultFnc.call(this,sugg.concat(results));
}
L.Control.Geocoder.Nominatim.prototype.geocode.call(that,query, callback, context);
}
})
Then you have to use the new Geocoder Class:
var geocoder = new L.CustomGeocoder({});
var control = L.Routing.control({
waypoints: [],
router: new L.Routing.osrmv1({
language: 'en',
profile: 'car'
}),
geocoder: geocoder
}).addTo(map);
And finally you can add suggestions over markers and theier title option over createSuggestionFromMarker(marker) or setSuggestions(arr):
var suggestions = [
{
name: 'Test Car 1',
center: [50.27, 19.03]
},
{
name: 'Test Car 2',
center: [50.10, 18.4]
}
];
geocoder.setSuggestions(suggestions);
var marker_work = L.marker([50.27, 19.03], { title: 'MyWork'}).addTo(map);
var marker_home = L.marker([50.10, 18.4], { title: 'MyHome'}).addTo(map);
geocoder.createSuggestionFromMarker(marker_work);
geocoder.createSuggestionFromMarker(marker_home);
Update, use marker Ref instead of fix latlng
Change this two function, then the marker is referenced and it always searches from the current position of the marker:
createSuggestionFromMarker(marker){
this.suggestions.push({name: marker.options.title, marker: marker});
},
getResultsOfSuggestions(query){
var results = [];
this.suggestions.forEach((point)=>{
if(point.name.indexOf(query) > -1){
if(point.marker){
point.center = point.marker.getLatLng();
}
point.center = L.latLng(point.center);
point.bbox = point.center.toBounds(100);
results.push(point);
}
});
return results;
},
You can test this in the demo, when you drag the marker
https://jsfiddle.net/falkedesign/hu25jfd1/
Related
Good Morning.
To work with wfs layer is it better to use leaflet or openlayers?
I have a code with openlayers that returns WFS from the geoserver. But I'm not able to show the attributes in popup. can anybody help me?
Thanks
You can try ol-ext ol/Overlay/PopupFeature to display feature attributes in a popup.
See example: https://viglino.github.io/ol-ext/examples/popup/map.popup.feature.html
Following the example of https://viglino.github.io/ol-ext/examples/popup/map.popup.feature.html, I have this code where my WFS layer contains the id and name attributes, however, it doesn't show anything in the popup
var vectorSource = new ol.source.Vector({
format: new ol.format.GeoJSON(),
url: function(extent) {
return 'http://localhost:8080/geoserver/teste/wfs?service=WFS&' +
version=1.1.0&request=GetFeature&typename=teste:MYLAYER&' +
'outputFormat=application/json&srsname=EPSG:4326&' +
'bbox=' + extent.join(',') + ',EPSG:4326';
},
strategy: ol.loadingstrategy.bbox
});
var vector = new ol.layer.Vector({
source: vectorSource,
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'rgba(0, 0, 255, 1.0)',
width: 2
})
})
});
var layers = [
new ol.layer.Tile({source: new ol.source.OSM()}),
vector,
];
var map = new ol.Map({
layers: layers,
interactions: ol.interaction.defaults({ altShiftDragRotate:false, pinchRotate:false }),
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat([-46.444137, -23.713596]),
zoom: 12
})
});
var select = new ol.interaction.Select({
hitTolerance: 5,
multi: true,
condition: ol.events.condition.singleClick
});
map.addInteraction(select);
var popup = new ol.Overlay.PopupFeature({
popupClass: 'default anim',
select: select,
canFix: true,
template: {
title:
function(f) {
return f.get('nome')+' ('+f.get('id')+')';
},
attributes: // [ 'id', 'nome' ]
{
'nome': { title: 'Nome' },
'id': { title: 'Id' },
}
}
});
map.addOverlay (popup);
This is the popup code. I have 3 layers: layer1, layer2 and layer3.
For layer1, ID I want to show as ID. For layer2, I want to show ID as CODE and for other layers I don't want to show ID attribute.
How should I change the template? Thanks
var popup = new ol.Overlay.PopupFeature({
popupClass: 'default anim',
select: select_interaction,
canFix: true,
template: {
title:
function(f) {
return f.get('NAME')+' ('+f.get('ID')+')';
},
attributes:
{
'ID': { title: 'ID' },
// with prefix and suffix
'POP': {
title: 'População', // attribute's title
before: '', // something to add before
format: ol.Overlay.PopupFeature.localString(), // format as local string
after: ' hab.' // something to add after
},
}
}
});
#user12538529
You have to create a function and return the template for each case:
// Create templates
var templateID = { ... };
var templateCODE = { ... };
// Popup with a template function
var popup = new ol.Overlay.PopupFeature({
popupClass: 'default anim',
select: select_interaction,
canFix: true,
template: function(feature) {
var prop = feature.getProperties();
// Test if has property ID
if (prop.hasOwnProperty('ID')) return templateID;
// or property CODE
else if (prop.hasOwnProperty('CODE')) return templateCODE;
}
});
In application I have Bing Maps API (Release Branch). Today suddenly I saw something wrong with direction module. I have set below mentioned direction modules option which were working earlier but not now. In below code I am trying to hide route and waypoints. It works for waypoints but not for route.
So I tried bing map SDK online example where I try to set routeDraggable : false but in the SDK example is not working.
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', () => {
that.directionsManager = new Microsoft.Maps.Directions.DirectionsManager(that.map);
// Set Route Mode to driving
that.directionsManager.setRequestOptions({
routeMode: Microsoft.Maps.Directions.RouteMode.driving,
routeDraggable: false
});
that.directionsManager.setRenderOptions({
drivingPolylineOptions: {
strokeColor: 'green',
strokeThickness: 3,
visible: false
},
waypointPushpinOptions: { visible: false },
viapointPushpinOptions: { visible: false },
autoUpdateMapView: false
});
const waypoint1 = new Microsoft.Maps.Directions.Waypoint({
location: new Microsoft.Maps.Location(startLoc.latitude, startLoc.longitude), icon: ''
});
const waypoint2 = new Microsoft.Maps.Directions.Waypoint({
location: new Microsoft.Maps.Location(endLoc.latitude, endLoc.longitude)
});
this.directionsManager.addWaypoint(waypoint1);
this.directionsManager.addWaypoint(waypoint2);
// Add event handler to directions manager.
Microsoft.Maps.Events.addHandler(this.directionsManager, 'directionsUpdated', function (e) {
// const that = this;
console.log(e);
var routeIndex = e.route[0].routeLegs[0].originalRouteIndex;
var nextIndex = routeIndex;
if (e.route[0].routePath.length > routeIndex) {
nextIndex = routeIndex + 1;
}
var nextLocation = e.route[0].routePath[nextIndex];
var pin = that.map.entities.get(index);
// var bearing = that.calculateBearing(startLoc,nextLocation);
that.MovePinOnDirection(that, e.route[0].routePath, pin, truckUrl, truckIdRanId);
});
this.directionsManager.calculateDirections();
});
https://www.bing.com/api/maps/sdk/mapcontrol/isdk/directionsgetrequestoptions
#rbrundritt Can you help me in this issue ?
My problem is the following:
Linestring with two or more lines on the one or more coordinates.
With several LineStrings only one string is shown in the map, I know, the LineStrings also use the same coordinates.
Is there a way that the LineStrings can use one and the same coordinates, but a shift of the line (to have for example three lines next to each other) takes place in the structure of the map?
The code is a bit better, which explains a lot:
var logoElement = document.createElement ('a');
logoElement.href = 'http://www.schienenpost.de/';
logoElement.target = '_blank';
var logoImage = document.createElement ('img');
logoImage.src = 'http://www.schienenpost.de/schienenpost.png';
logoElement.appendChild (logoImage);
var iconStyle = new ol.style.Style ({
image: new ol.style.Icon (/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 1.0],
src: 'http://www.schienenpost.de/marker/marker.png'
}))
});
var scaleLineControl = new ol.control.ScaleLine();
var markerStartEnd = function (layer,feature) {
var i, iconFeature, iconFeatures = [], coordinates, nameLine;
coordinates = feature.getGeometry ().getCoordinates ();
nameLine = feature.getProperties () ['name'];
i = 0;
iconFeature = new ol.Feature ({
geometry: new ol.geom.Point (coordinates[i]),
name: 'Start'+nameLine,
});
iconFeature.setStyle (iconStyle);
iconFeatures.push (iconFeature);
i = coordinates.length - 1;
iconFeature = new ol.Feature ({
geometry: new ol.geom.Point (coordinates[i]),
name: 'End'+nameLine,
});
iconFeature.setStyle (iconStyle);
iconFeatures.push (iconFeature);
layer.getSource ().addFeatures (iconFeatures);
};
var layerLines = new ol.layer.Vector ({
source: new ol.source.Vector ({
format: new ol.format.GeoJSON (),
url: 'schienenpost.geojson',
useSpatialIndex: false
}),
style: new ol.style.Style ({stroke: new ol.style.Stroke ({color : 'red', width: 3})}),
});
var layerMarker = new ol.layer.Vector ({
title: 'Marker',
source: new ol.source.Vector ()
});
var element = document.getElementById ('popup');
var popup = new ol.Overlay ({
element: element,
positioning: 'bottom-center',
stopEvent: false,
offset: [0, -0]
});
var map = new ol.Map ({
controls: ol.control.defaults ()
.extend ([
new ol.control.OverviewMap (),
new ol.control.FullScreen (),
scaleLineControl
]),
//target 'map',
target: document.getElementById ('map'),
layers: [
new ol.layer.Tile ({
source: new ol.source.OSM ()
}),
],
view: new ol.View ({
center: ol.proj.fromLonLat ([10.627, 53.620]),
zoom: 8
}),
logo: logoElement
});
map.addOverlay (popup);
map.addLayer (layerLines);
map.addLayer (layerMarker);
map.once ('moveend', function(e) {
layerLines.getSource ().getFeaturesCollection ().forEach (function (feature) {
markerStartEnd (layerMarker,feature);
});
});
map.on ('click', function (evt) {
var feature = map.forEachFeatureAtPixel (evt.pixel,
function (feature) {
return feature;
});
if (feature) {
var coordinates = feature.getGeometry ().getCoordinates ();
var clickpoint = map.getCoordinateFromPixel (evt.pixel);
if (!isNaN (coordinates [0])) { // Punkt
popup.setPosition (coordinates);
} else if (!isNaN (coordinates [0][0])) { // Linie
popup.setPosition (clickpoint);
} else { // kein brauchbares feature
$ (element).popover ('destroy');
return;
}
$ (element).popover ({
'placement': 'top',
'html': true,
'content': feature.get ('name')
});
$ (element).popover ().data ('bs.popover').options.content = feature.get ('name');
$ (element).popover ('show');
} else {
$ (element).popover ('hide');
}
});
map.on ('pointermove', function(e) {
if (e.dragging) {
$ (element).popover ('destroy');
return;
}
var pixel = map.getEventPixel (e.originalEvent);
var hit = map.hasFeatureAtPixel (pixel);
map.getTarget ().style.cursor = hit ? 'pointer' : '';
});
// inital Locations
var myLocations = [{
name: "Istanbul",
address: "214 S Highland Ave, Pittsburgh, PA",
latlng: {
lat: 41.008238,
lng: 28.978359
}
}, {
name: "Antalya",
address: "5469 Penn Ave Pittsburgh, PA 15206",
latlng: {
lat: 36.896891,
lng: 30.713323
}
}, {
name: "Ankara",
address: "236 Fifth Ave Pittsburgh, PA 15222",
latlng: {
lat: 39.933363,
lng: 32.859742
}
}, {
name: "Trabzon",
address: "5608 Walnut St Pittsburgh, PA 15232",
latlng: {
lat: 41.002697,
lng: 39.716763
}
}, {
name: "Bursa",
address: "5841 Penn Ave Pittsburgh, PA 15206",
latlng: {
lat: 40.188528,
lng:29.060964
}
},
];
//String to display in info window
//Declare Map variable and markers array
var map;
var infoWindow;
var marker;
//Create Instance of a map from the Google maps api
//Grab the reference to the "map" id to display map
//Set the map options object properties
function initMap() {
map = new google.maps.Map(document.getElementById("map"), {
center: {
lat: 38.963745,
lng: 35.243322
},
zoom: 5,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControl: true,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.DROPDOWN_MENU
}
});
};
// tells the view model what to do when a change occurs
function mLocation(value) {
this.name = ko.observable(value.name);
this.address = ko.observable(value.address);
this.description = ko.observable(value.description);
this.latlng = ko.observable(value.lat);
};
//ViewModel
function ViewModel() {
var self = this;
self.markers = [];
//Copies the values of initialLocations and stores them in sortedLocations(); observableArray
self.sortedLocations = ko.observableArray(myLocations);
//Adds new markers at each location in the initialLocations Array
self.sortedLocations().forEach(function(location) {
marker = new google.maps.Marker({
position: location.latlng,
map: map,
title: location.name,
icon: 'img/marker.png',
animation: google.maps.Animation.DROP
});
location.marker = marker;
var content = '<div id="iw_container">' +
'<div class="iw_title">' + name + </div>';
//Pushes each marker into the markers array
this.markers.push(marker);
});
//Map info windows to each item in the markers array
self.markers.map(function(info) {
infoWindow = new google.maps.InfoWindow({
content: content
});
//Add click event to each marker to open info window
info.addListener('click', function() {
infoWindow.open(map, this),
info.setAnimation(google.maps.Animation.BOUNCE) //Markers will bounce when clicked
setTimeout(function() {
info.setAnimation(null)
}, 2000); //Change value to null after 2 seconds and stop markers from bouncing
});
});
//Click on item in list view
self.listViewClick = function(loc) {
if (loc.name) {
map.setZoom(15); //Zoom map view
map.panTo(loc.latlng); // Pan to correct marker when list view item is clicked
loc.marker.setAnimation(google.maps.Animation.BOUNCE); // Bounce marker when list view item is clicked
infoWindow.open(map, loc.marker); // Open info window on correct marker when list item is clicked
}
setTimeout(function() {
loc.marker.setAnimation(null); // End animation on marker after 2 seconds
}, 2000);
};
// Stores user input
self.query = ko.observable('');
//Filter through observableArray and filter results using knockouts utils.arrayFilter();
self.search = ko.computed(function() {
return ko.utils.arrayFilter(self.sortedLocations(), function(listResult) {
return listResult.name.toLowerCase().indexOf(self.query().toLowerCase()) >= 0;
});
});
};
$(document).ready(function() {
initMap();
ko.applyBindings(ViewModel());
});
I would like to ask about how to add an info window to a marker in Google Maps. The condition is, I have to create a program with multiple markers on a map. But how I can give a specified info window to each marker when select in each place in the view list?
I'm trying to add markers to a map using the
L.mapbox.featureLayer({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [ll[0], ll[1]]
},
properties: {
title: d[i].screen_name,
media: d[i].media_url,
id: d[i].source_id,
text: d[i].text,
userId: d[i].user_id,
'marker-color': '#000',
'marker-symbol': 'star-stroked'
}
}).addTo(map);
method but how do I from there access that marker? map.getLayerAt(0) or something?
It doesn't; display on the map for some reason..
Mocked this up quickly based on an example on the Mapbox site:
var map = L.mapbox.map('map', 'examples.map-zr0njcqy');
map.featureLayer.on('ready', function(e) {
var markers = [];
this.eachLayer(function(marker) { markers.push(marker); });
cycle(markers);
});
function cycle(markers) {
var i = 0;
function run() {
if (++i > markers.length - 1) i = 0;
var marker = markers[i];
console.log(marker.getLatLng());
}
run();
}
You can use the cycle() function to do stuff with each individual marker - if you look in the console you'll see that you can know access the marker's internal properties like latLng etc. I don't know what you want to do with each marker, so if you provide more information I'll be able to assist you more!