Comments (28)
Tried the code provided by @perfahlen and it works fine after adding a subscription key to the map options. I've added a modified version of Perfahlen's code to the sample site here: https://azuremapscodesamples.azurewebsites.net/index.html?sample=Get%20closest%20HTML%20marker%20to%20position
@sujayvsarma Can you verify that your are pointing to version 2 of the Azure Maps Web SDK (check the javascript URL and make sure if has "mapcontrol/2/atlas.min.js" in it. If it doesn't have then you are likely pointing to a really old version that doesn't have the html marker manager.
Just a general piece of feedback, if you are trying to load a lot of points on the map (more than a few hundred) consider using a data source and the symbol or bubble layer instead of HTML markers. HTML markers create DOM elements on the page and the more DOM elements on a page, the slower the page becomes (standard web dev problem). The data source and symbol/bubble layers support hundreds of thousands of points with good performance. This is noted in this documentation on HTML markers. I have put together a sample for this scenario here: https://azuremapscodesamples.azurewebsites.net/index.html?sample=Get%20closest%20point%20to%20position
from azuremapscodesamples.
Tagging @walsehgal, @stack111, @rbrundritt
from azuremapscodesamples.
@sujayvsarma , if your dataset is small, less than a couple of hundred points you can use azure maps math library, getDistanceTo: https://docs.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.math?view=azure-maps-typescript-latest#getdistanceto-position---point--position---point--string---distanceunits- and simple loop over them to find the closest point. However, this is not to recommend if it's a task you using frequently, it is a task rarely used. Otherwise you need to find another solution.
or you can use https://docs.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.math?view=azure-maps-typescript-latest#getclosestpointongeometry-position---point---feature-point--any---atlas--string---distanceunits--number- but this method requires you to create a multipoint of all the other points first.
Example using
var p1 = new atlas.data.Point([20, 60]);
var p2 = new atlas.data.Point([10, 50]);
console.log(atlas.math.getDistanceTo(p1, p2));
from azuremapscodesamples.
@perfahlen - Yeah so to be able to get to that calculation, I need to get the data out of the marker. How do I get the marker and its data from atlas
after I have added it?
from azuremapscodesamples.
@sujayvsarma for example, shape.data
from azuremapscodesamples.
What.. no, you cant get it that way. Here is what I have done.
I get the custom POI information (in my case, these are airports) from a different data source. These are added to the map using this code:
var marker = new atlas.HtmlMarker({
htmlContent: amSvg,
color: '#343a40',
text: data[0].iata,
position: [data[0].geoLocation.lon, data[0].geoLocation.lat]
});
map.markers.add(marker);
(amSvg
is an SVG pin shape).
Both the HtmlMarker
and the map itself have click events attached. They both fire correctly.
When the click is on the HtmlMarker
, I can get the data I want (in this case, the text
value) using e.target.options.text
.
BUT, when the click is on the map, I want to know if the user has clicked on the Azure Maps control's own POI for that same airport. I can get to this using:
if ((e.shapes[0].type === 'Feature') && (e.shapes[0].layer.id === 'Airport label'))
and then examining the properties therein.
BUT, what I want to do here is, I want to get the nearest HtmlMarker
to the Maps' own POI position and move the user to that instead.
from azuremapscodesamples.
To clarify -- I want to start with an Azure Maps' POI and move to a (the nearest) custom HtmlMarker
.
from azuremapscodesamples.
@sujayvsarma you should be able to get position from
marker.getOptions().position
from azuremapscodesamples.
If you don't know the answer, please don't spam the thread with irrelevant answers. It serves no purpose. At least you should read the question and respond to that.
How do I get the marker?????? That is my biggest problem.
Find nearest HtmlMarker to click position
That is what I want.. I don't know how to get it.
from azuremapscodesamples.
sorry @sujayvsarma , no need not to keep a good tone. I should have read your problem more thorough,
I made an example that locates the nearest HTML marker clicked and color that marker blue for 1.5 seconds. Hope it helps
<html>
<head>
<title>
</title>
<link
rel="stylesheet"
href="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.css"
type="text/css"
/>
<script src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
<script type="text/javascript">
var map;
function GetMap() {
map = new atlas.Map("myMap", {
view: "Auto",
authOptions: {
authType: "subscriptionKey",
subscriptionKey: "<KEY HERE>"
}
});
map.events.add("ready", function() {
map.markers.add(
new atlas.HtmlMarker({
htmlContent:
'<div style="width: 10px; height: 10px; background-color: red"></div>',
position: [0, 0]
})
);
map.markers.add(
new atlas.HtmlMarker({
htmlContent:
'<div style="width: 10px; height: 10px; background-color: red"></div>',
position: [50, 50]
})
);
});
map.events.add("click", function(evt) {
let position = evt.position;
let markers = map.markers.getMarkers();
let closestMarker = {};
markers.forEach(marker => {
if (!closestMarker.marker) {
closestMarker.marker = marker;
closestMarker.distance = atlas.math.getDistanceTo(
new atlas.data.Point(marker.getOptions().position),
new atlas.data.Point(evt.position)
);
}
let distance = atlas.math.getDistanceTo(
new atlas.data.Point(marker.getOptions().position),
new atlas.data.Point(evt.position)
);
if (distance < closestMarker.distance) {
closestMarker.marker = marker;
closestMarker.distance = distance;
}
});
let options = closestMarker.marker.getOptions();
closestMarker.marker.setOptions({
htmlContent:
'<div style="width: 10px; height: 10px; background-color: blue"></div>'
});
setTimeout(() => {
closestMarker.marker.setOptions({
htmlContent:
'<div style="width: 10px; height: 10px; background-color: red"></div>'
});
}, 1500);
});
}
</script>
</head>
<body onload="GetMap()">
<div
id="myMap"
style="position:relative;width:100%;min-width:290px;height:600px;background-color:gray"
></div>
</body>
</html>
from azuremapscodesamples.
I already tried this before posting here. I get runtime JavaScript errors that these are not implemented:
let markers = map.markers.getMarkers()
Error message that markers
doesn't implement getMarkers
.
markers.forEach(marker...
Error message that markers
doesn't implement forEach
.
I tried the statements directly in the F12 console as well, same result.
from azuremapscodesamples.
I am pointing to v2 of the SDK. This is my script
line:
<script type="text/javascript" src="https://atlas.microsoft.com/sdk/javascript/mapcontrol/2/atlas.min.js"></script>
How do I adapt the HtmlMarker
way to using a SymbolLayer
instead? I could not find any documentation. How would I go about getting custom POI information into a data source that the SymbolLayer
uses?
This is the thing.. There is hardly any documentation around these things!
What browser are you folks using? I am using Microsoft Edge (on Win10).
from azuremapscodesamples.
I got it to work. Finally! Had a typo in the code. Instead of map.markers.getMarkers()
, I was doing map.Markers.getMarkers()
(with a capital M
on the property).
Now, can you help me for this?
How do I adapt the HtmlMarker way to using a SymbolLayer instead? I could not find any documentation. How would I go about getting custom POI information into a data source that the SymbolLayer uses?
from azuremapscodesamples.
I provided a like in my response to a sample that does exactly what you asked using a symbol layer. There is a source code button on all samples.
There is a ton of documentation on Azure maps. I recommend going through the how to guides for the web SDK first https://docs.microsoft.com/en-us/azure/azure-maps/how-to-use-map-control
Look at the tavle of contents on the side to see all the different topics. I recommend you start with the create a data source doc then going to the add a symbol layer doc. There is also over 150 code samples here https://azuremapscodesamples.azurewebsites.net
from azuremapscodesamples.
Do you know of a practical threshold beyond which a collection of HtmlMarker
s would start affecting performance? In my scenario, I am expecting to have at most 10 such markers.
from azuremapscodesamples.
Depends on device but usually around 300 you might notice a bit off a hit. Over 1000 and you will certainly notice. If only using 10 html markers then you are fine.
from azuremapscodesamples.
Oh. I should be okay then. :)
Question for @rbrundritt :
When using the Closest Marker
calculation code from your samples above (I actually took the one from your sample, it sometimes finds locations that are off. For example, in your own sample, you can see how it sometimes finds markers in a different geographical country.
Is there a way to restrict the math by geographic boundaries? As discussed above, my UX is about airports. I don't want to show the user that the closest airport to a point is in a different country (while mathematically true, it would be practically undesirable).
from azuremapscodesamples.
That can be achieved as well, but if you don't want users to go there, then perhaps the better approach is not to show them on the map in the first place.
To verify, is the airport data from the Azure Maps POI service?
Do you want the user to be able to click anywhere in the world and then based on where they clicked, limit the nearest airport for the country they clicked in?
If they click on water, what do you want to do?
from azuremapscodesamples.
is the airport data from the Azure Maps POI service?
No. We've already discussed Azure POI data and it's usability for my purpose in another item. Don't want to go there again.
Do you want the user to be able to click anywhere in the world and then based on where they clicked, limit the nearest airport for the country they clicked in?
Yes.
If they click on water, what do you want to do?
Physically nearest would be suitable, I guess.
from azuremapscodesamples.
Does your airport data have country iso codes as properties or some other information we can use to link them to a country? If not, then there are a couple of different approaches. One is to enrich the data with that info. If you have this already, then great otherwise passing all airports through a reverse geocoder would work, but wouldn't be very good for costs. The other is to retrieve the boundary for country then doing a point in polygon search. Not ideal in terms of costs.
from azuremapscodesamples.
Yes, the airport data has country codes. But, how would I add this metadata to the HtmlMarker?
from azuremapscodesamples.
Solution 1
You can use HtmlMarkerLayer as @rbrundritt's example here https://github.com/Azure-Samples/AzureMapsCodeSamples/tree/master/AzureMapsCodeSamples/HTML%20Markers/HtmlMarkerLayer
Solution 2
I'm not sure if this is ok with license agreement. You need to handle the attributes yourself. One way is to simple extend HTML Marker with your own getter and setter.
atlas.HtmlMarker.prototype.setCountry = function(country){
this._country = country;
};
atlas.HtmlMarker.prototype.getCountry = function(){
return this._country;
};
then you can simple
marker.setCountry('a');
and to access it you can
marker.getCountry();
Solution 3
or you can simple hide it your htmlContent like
<div style="width: 10px; height: 10px; background-color: red;" data-country="a"></div>
and filter it when you iterate markers.
from azuremapscodesamples.
To attach custom data to HTML Markers you can add your data to a custom property of the class. We recommend using "property" for consistency with the rest of the map API. This is similar to what PreFahlen's solution 2 above, but just a property rather than getters/setters. For example, lets assume your data is in GeoJSON format, you can add the properties to the marker like so:
var myDataPoint = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
},
properties: {
countryIso: 'US'
}
};
var marker = new atlas.HTMLMarker({
position: myDataPoint.geometry.coordinate
});
//Attach the properties to the marker.
marker.properties = myDataPoint.properties;
Later, when you retrieve the marker from say a calculation, it will have your customer data available on the "properties" property of the marker. You can do this kind of thing with pretty much any element in HTML. This is a general web development thing and not specific to Azure Maps.
Now, lets assume you have an array of markers similar to the one above added to the map and you want to find the closest one that is in the country the user clicked in. The first step is to find out what country the user clicked in. There are two ways to do this;
- Use a reverse geocoding service. This will generate a transaction, but would be a supported method. I have attached a code sample using this approach to this post. I used some of airport data from here http://ourairports.com/data/airports.csv to create a geojson file to power the sample.
- This is an unsupported method currently, but something we actually do under the hood of the map control to power the screen reader for those with limited vison. The map uses vector tiles to render the base map. These vector tiles has the raw map data in it, like country boundaries and road lines. All road data have a country ISO 3 value on them. You can access the base map data using some undocumented functions. This method would only work if there is road data rendered on the map and wouldn't be perfect, but it would be practically free (only cost being that map tiles have to be rendered, which you likely want anyways). Since this approach is a decent amount of work, error prone and not currently supported I won't put together a sample for this at the moment, but something that might be worth experimenting with. I have a sample showing how to access this data here: https://azuremapscodesamples.azurewebsites.net/experimental/Inspect%20features%20under%20the%20mouse.html The source code is here: https://github.com/Azure-Samples/AzureMapsCodeSamples For fun I tried a large data set of 9,000+ airports, loading and moving the map were slow, but the search logic in this sample worked fast. If you are interested in giving this a try replace airport.js with airport_big.js in the script tag at the top of the html file.
from azuremapscodesamples.
I had a theory I could add custom data to properties and stuff. But I wasn't sure if the control's existing code would play nice with that. For example, what if I added something that internally meant something else? Or the values got overwritten by other code? Seemed to be iffy to go that route, with a lot of trial and error.
#2 -- I was looking at your hosted sample. It looks like the data is only available if you click on a road. If you click somewhere else (like a "built-up area" or the name of the city), then the data is not available. Since I cannot force the user to only click on roads, this solution doesn't seem feasible in my scenario :( Though the sample and how could do that was very interesting.
from azuremapscodesamples.
Yes, if you created a customer property with the same name of an existing property it would break things. That's why we recommend using the name "properties" or "metadata". Internally we know not to use those and have documented that for layers (need to update docs for HTML markers).
For #2, that sample just grabs when you clicked on, but the code can easily be modified to grab the closest road that has been loaded on the map. This approach is more complex, but as I said wouldn't generate any cost. What you could do, if you want the cheapest possible option, is to combine both methods. Try and get the nearest road, but set a threshold. If the road is more than x miles away from where the user clicked or no road found, fallback to reverse geocoder.
from azuremapscodesamples.
Thank you @rbrundritt. You have been more than helpful :)
I shall now close this item because I believe I have no further questions at this time.
from azuremapscodesamples.
@rbrundritt - What's your MS alias? Wanted to e-mail you (off this public channel)
from azuremapscodesamples.
richbrun
from azuremapscodesamples.
Related Issues (20)
- Fill Address Form with Autosuggest Uncaught (in promise) TypeError: Failed to fetch running sample code HOT 3
- Map 3.0.0 Preview 8-->10 Drawing Manager Issues after changing the map style HOT 1
- Drawing Manager Event Fires for an drawn shape when clicking outside of the shape HOT 1
- Map Popup with HTML Bootstrap 5 Components wont Interact HOT 3
- [How To] How to generate tokens without RBAC? HOT 2
- [HowTo] Bring back old map styles HOT 1
- atlas.io.read does not load icons from the kmz file HOT 1
- New layers... who dis? HOT 5
- Missing npm package azuremaps-maplibre-gl HOT 5
- Missing supported type on BoundingBox.fromData HOT 4
- invalid HTML in sample HOT 1
- Usage of the ['id'] data expression HOT 4
- Choosing popup locale for formatting data HOT 3
- Changing map style changes layering HOT 10
- I am unable to access some resources. HOT 3
- Adding method to data source to allow string Geojson HOT 4
- Image based Choropleth HOT 3
- I have a problem with running debugging this azuremapscodesample app it won't run I get this error shown in screenshot HOT 18
- How do I make a uwp app like google earth using Azure maps web SDK via a WebView in mainpage.xml MainPage.xaml.cs with search bar on visual studio 2022
- How do I make a web app like google earth using the Azure Maps Web SDK via a WebView in mainpage.xml mainpage.xml.cs with search bar on visual studio 2022
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from azuremapscodesamples.