Open LeviateK opened 2 years ago
Hi @LeviateK, sorry for the delay. It doesn't look like much to do, I'll try to take a look as soon as I find time to work on this.
Thanks @arnaudleclerc - appreciate you taking a look at it. I've used it with the native javascript with 1 custom icon, but struggle to get other icons for different data sets. My full map design would then include a popup per symbol with a link to a details page.
This will have to be delayed a little bit more, sorry for that, but I didn't forget about it. I cannot find any time to work on this currently. I will let you know as soon as any progress is made
No worries mate, I've got part of it working with the native JavaScript, and am at least 6 weeks out from needed this.
In desperate need of this feature as well...
@LeviateK could you share me the solution you used in native Javascript for this? I really need to get this fixed too
@arnvanhoutte Absolutely - I am far from a Javascript expert and constantly ran into syntax issues, but this is what I came up with based on official documentation and some samples. This is in a ASP.NET Core project with Razor pages, so the cshtml.cs OnLoad gets my locations with EntityType as the differentiator passed through via ViewBag, which are then mapped to the iconSprites. I also used clustering, reducing initial data points on load. Let me know if you have any questions.
`
var map, dataSource, popup;
//Note that the typeahead parameter is set to true.
var geocodeServiceUrlTemplate = 'https://atlas.microsoft.com/search/{searchType}/json?typeahead=true&subscription-key={subscription-key}&api-version=1&query={query}&language={language}&lon={lon}&lat={lat}';
//URL to fetch Access token
var url = 'https://adtokens.azurewebsites.net/api/HttpTrigger1?code=dv9Xz4tZQthdufbocOV9RLaaUhQoegXQJSeQQckm6DZyG/1ymppSoQ==';
//Define an HTML template for a custom popup content laypout.
var popupTemplate = '<div class="customInfobox"><div class="name">{name}</div>{description}</div>';
function GetMap()
{
//Initialize a map instance.
map = new atlas.Map('myMap', {
//Add your Azure Maps subscription key to the map SDK. Get an Azure Maps key at https://azure.com/maps
center: [-33.33, 35.641],
zoom: 1.5,
style: 'grayscale_dark',
authOptions: {
authType: 'subscriptionKey',
subscriptionKey: '#YourKeyHere',
getToken: function (resolve, reject, map) {
fetch(url).then(function (response) {
return response.text();
}).then(function (token) {
resolve(token);
});
}
}
});
//Wait until the map resources are ready.
// Add all the icons -- wwwroot/images
map.events.add('ready', function () {
// Build array of custom icons
var iconPromises = [
map.imageSprite.add('icon1', '../images/image1.png'),
map.imageSprite.add('icon2', '../images/image2.png')
// Add more icons here if necessary
];
Promise.all(iconPromises).then(function ()
{
// Map Controls Section
/* Construct and add a compass control*/
var compassControl = new atlas.control.CompassControl();
map.controls.add(compassControl, {
position: "bottom-right"
});
/* Construct and add a zoom control*/
var zoomControl = new atlas.control.ZoomControl();
map.controls.add(zoomControl, {
position: "bottom-right"
});
/* Construct and add a pitch control*/
var pitchControl = new atlas.control.PitchControl();
map.controls.add(pitchControl, {
position: "bottom-right"
});
/* Construct and add a style control*/
var styleControl = new atlas.control.StyleControl();
map.controls.add(styleControl, {
position: "bottom-right"
});
// End of Map Controls Section
// Add Data Source
//Create a data source and add it to the map.
dataSource = new atlas.source.DataSource(null, {
cluster: true,
clusterRadius: 5,
clusterMaxZoom: 2
});
map.sources.add(dataSource);
// Pull from code-behind for project data
@{
List<Project.Models.MapData> perDiems = ViewBag.Locations;
var dLocations = perDiems.Distinct().ToList();
}
@for (int i = 0; i < dLocations.Count(); i++)
{
<text>
var point_@i = new atlas.data.Feature(new atlas.data.Point(['@dLocations[i].LONG', '@dLocations[i].LAT']),
{
Name: '@dLocations[i].City',
Description: '@dLocations[i].State',
EntityType: '@dLocations[i].EntityType'
});
dataSource.add([point_@i]);
</text>
}
//Add Layer for clusters
// EntityType for determining which icon to use
var clusterLayer = new atlas.layer.SymbolLayer(dataSource, null, {
iconOptions: {
image:
[
'match',
['get', 'EntityType'],
'1','icon1',
'2','icon2',
'icon1'
],
allowOverlap: true
},
textOptions: {
textField: ['get', 'point_count_abbreviated'],
offset: [-0.25, -1.65]
},
filter: ['has', 'point_count']
});
map.layers.add(clusterLayer);
// Add a layer for rendering point data as symbols.
// Create a layer to render point data.
var symbolLayer = new atlas.layer.SymbolLayer(dataSource, null, {
iconOptions: {
image:
[
'match',
['get', 'EntityType'],
'1','icon1',
'2','icon2',
'icon1'
],
allowOverlap: true
//ignorePlacement: true
},
filter: ['!', ['has', 'point_count']]
});
map.layers.add(symbolLayer);
//Create a popup but leave it closed so we can update it and display it later.
popup = new atlas.Popup({
pixelOffset: [0, -50]
});
//Add a click event to the symbol layer.
map.events.add('click', symbolLayer, symbolClicked);
});
// Popup clicked shows location
function symbolClicked(e) {
//Make sure the event occured on a point feature.
if (e.shapes && e.shapes.length > 0) {
var content, coordinate;
//Check to see if the first value in the shapes array is a Point Shape.
if (e.shapes[0] instanceof atlas.Shape && e.shapes[0].getType() === 'Point') {
var properties = e.shapes[0].getProperties();
content = popupTemplate.replace(/{name}/g, properties.Name).replace(/{description}/g, properties.Description);
coordinate = e.shapes[0].getCoordinates();
} else if (e.shapes[0].type === 'Feature' && e.shapes[0].geometry.type === 'Point') {
//Check to see if the feature is a cluster.
if (e.shapes[0].properties.cluster) {
content = '<div style="padding:10px;">Cluster of ' + e.shapes[0].properties.point_count + ' symbols</div>';
} else {
//Feature is likely from a VectorTileSource.
content = popupTemplate.replace(/{name}/g, properties.Name).replace(/{description}/g, properties.Description);
}
coordinate = e.shapes[0].geometry.coordinates;
}
if (content && coordinate) {
//Populate the popupTemplate with data from the clicked point feature.
popup.setOptions({
//Update the content of the popup.
content: content,
//Update the position of the popup with the symbols coordinate.
position: coordinate
});
//Open the popup.
popup.open(map);
}
}
}
});
}
</script>`
To have it render, body tag looks like this:
<body onload="GetMap()">
Hi Arnaud - Similar to your Symbol example where it is tied to a datasource, I have a need to add custom imageSprites so the data points can be easily assigned. I have a solution in use with 1 custom image sprite using the standard javascript control, but would much prefer to use this package for it's simplicity if this feature were to exist. The ImageLayer requiring 4 points does not work, as my data is LAT/LON.
azure-maps-control reference: https://docs.microsoft.com/en-us/javascript/api/azure-maps-control/atlas.imagespritemanager?view=azure-maps-typescript-latest
Sample Custom Icon javascript located here: https://docs.microsoft.com/en-us/azure/azure-maps/map-add-pin