There is AmChart's amMap with images i.e. imageSeries. The objective is to change the clicked image or say validate the imageSeries without losing the zoom level. In dev mode, the image has been changed using imageURL but how to update it on the chart dynamically?
I took reference from the docs Amcharts4 imapimageseriesevents
Click on the area with dense colour i.e. Uttar Pradesh to see the images.
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create map instance
var chart = am4core.create("chartdiv", am4maps.MapChart);
// Set map definition
chart.geodata = am4geodata_indiaLow;
// Set projection
chart.projection = new am4maps.projections.Miller();
// Create map polygon series
var polygonSeries = chart.series.push(new am4maps.MapPolygonSeries());
//Set min/max fill color for each area
polygonSeries.heatRules.push({
property: "fill",
target: polygonSeries.mapPolygons.template,
min: chart.colors.getIndex(1).brighten(1),
max: chart.colors.getIndex(1).brighten(-0.3)
});
// Make map load polygon data (state shapes and names) from GeoJSON
polygonSeries.useGeodata = true;
// Set heatmap values for each state
polygonSeries.data = [
{
id: "IN-UP",
value: 5130632
}
];
// Set up heat legend
let heatLegend = chart.createChild(am4maps.HeatLegend);
heatLegend.series = polygonSeries;
heatLegend.align = "right";
heatLegend.valign = "bottom";
heatLegend.width = am4core.percent(20);
heatLegend.marginRight = am4core.percent(4);
heatLegend.minValue = 0;
heatLegend.maxValue = 40000000;
// Set up custom heat map legend labels using axis ranges
var minRange = heatLegend.valueAxis.axisRanges.create();
minRange.value = heatLegend.minValue;
minRange.label.text = "Little";
var maxRange = heatLegend.valueAxis.axisRanges.create();
maxRange.value = heatLegend.maxValue;
maxRange.label.text = "A lot!";
// Blank out internal heat legend value axis labels
heatLegend.valueAxis.renderer.labels.template.adapter.add("text", function(labelText) {
return "";
});
// Configure series tooltip
var polygonTemplate = polygonSeries.mapPolygons.template;
polygonTemplate.applyOnClones = true;
polygonTemplate.togglable = true;
polygonTemplate.tooltipText = "{name}";
polygonTemplate.nonScalingStroke = true;
polygonTemplate.strokeOpacity = 0.5;
polygonTemplate.fill = chart.colors.getIndex(0);
var lastSelected;
polygonTemplate.events.on("hit", function(ev) {
if (lastSelected) {
lastSelected.isActive = false;
}
ev.target.series.chart.zoomToMapObject(ev.target);
if (lastSelected !== ev.target) {
lastSelected = ev.target;
}
});
/* Create selected and hover states and set alternative fill color */
var ss = polygonTemplate.states.create("active");
ss.properties.fill = chart.colors.getIndex(4);
var hs = polygonTemplate.states.create("hover");
hs.properties.fill = chart.colors.getIndex(2);
var imageSeries = chart.series.push(new am4maps.MapImageSeries());
imageSeries.id = "markers";
var imageTemplate = imageSeries.mapImages.template;
imageTemplate.propertyFields.longitude = "longitude";
imageTemplate.propertyFields.latitude = "latitude";
imageTemplate.nonScaling = true;
let jsonSelected = [];
imageTemplate.events.on("hit", function(ev) {
ev.target.dataItem.dataContext.imageURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAAAY1BMVEX///8AAAD39/f19fUmJiYgICAdHR0sLCySkpL8/PwWFhbj4+Px8fEPDw/n5+ecnJw2Nja/v79zc3OKioqlpaW1tbVLS0t/f3/Gxsbd3d3Nzc3X19dUVFRubm6vr69oaGhAQEAk5whvAAAB+klEQVRYhe2Yi5KCIBSGBfGaJqmVabf3f8qVg02GYKgws83wzexOHekP+A+HwPP0aSltFzTXBz9QzwObV67RQG1Y+HJiqkXB/p8uBoVxxSSve8/bX9mrytisNCnTu/M3d/Y6bYwIZ9DRMnm9T0oYQrZdGaY37cahDkZRbBTuIqkKfF/UyT6hSXKGjNhNn+wgY87J9IkeB5iLo/zhEWblsEpYtE9kvZ0x+yCdXR0XytrEC4VbqrWmYfUvqlkZjPWhMdYMalapPStHtMAh8BopvBbYPSGvdPvheZChT0mGilTf7RPhdlZfWjX5qBLpAzUrn6tZ/k3XPhFu582f/e5oZb1sIvV4uX3fZmyGSmHnUIn265X7LUhasw6BfnbOACsiGK8IvuOVBnY8XL52UQ5UAmLo10tL3tWnI9y+BBsh4XaSbtiLUE6JMWg+/BRC1hh6bYGtO/6/APsf4LXxKXEafpDG6+ISJC6vist6LbYcelEp4qr2csi7R5EiTsbxSBGf4gejplgeD0Z7CSbyuJN20k7aSTtpJ+2knbSTdtJO+lelrR04VMeepXEJSw9xqris16HAcIQvFsZl2DtI/xoTr7fwmScmlYU8iUNz11qBkN1mbuI4tt2zi7XLOKtXiP2fueR4w6WDzGR6cLIApEML2YLTXrq2c/lZoPoPNtQibDMMVRwAAAAASUVORK5CYII=";
if ($.inArray(ev.target.dataItem.dataContext.id, jsonSelected) !== -1) {
jsonSelected.splice($.inArray(ev.target.dataItem.dataContext.id, jsonSelected), 1);
} else {
jsonSelected.push(ev.target.dataItem.dataContext.id);
}
$('#list').empty();
$.each(jsonSelected, (index, value) => {
$('#list').append('<div class="selected">' + value + '<i id="' + value + '" class="removeItem fas fa-times"></i></div>');
});
$(".selected .removeItem").click(function() {
jsonSelected.splice(jsonSelected.indexOf(+this.id), 1);
$(this).parents('.selected').remove();
});
});
var image = imageTemplate.createChild(am4core.Image);
image.propertyFields.href = "imageURL";
image.width = 20;
image.height = 20;
image.horizontalCenter = "middle";
image.verticalCenter = "middle";
imageSeries.data = [{
"id": 101,
"minZoomLevel": 2,
"latitude": 28.340322,
"longitude": 77.922881,
"imageURL": "data:image/png;base64,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",
"width": 5,
"height": 5,
"label": "[font-size:10]Meerut[/]"
}, {
"id": 102,
"minZoomLevel": 2,
"latitude": 30.340322,
"longitude": 78.922881,
"imageURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAAAY1BMVEX///8AAAD39/f19fUmJiYgICAdHR0sLCySkpL8/PwWFhbj4+Px8fEPDw/n5+ecnJw2Nja/v79zc3OKioqlpaW1tbVLS0t/f3/Gxsbd3d3Nzc3X19dUVFRubm6vr69oaGhAQEAk5whvAAAB+klEQVRYhe2Yi5KCIBSGBfGaJqmVabf3f8qVg02GYKgws83wzexOHekP+A+HwPP0aSltFzTXBz9QzwObV67RQG1Y+HJiqkXB/p8uBoVxxSSve8/bX9mrytisNCnTu/M3d/Y6bYwIZ9DRMnm9T0oYQrZdGaY37cahDkZRbBTuIqkKfF/UyT6hSXKGjNhNn+wgY87J9IkeB5iLo/zhEWblsEpYtE9kvZ0x+yCdXR0XytrEC4VbqrWmYfUvqlkZjPWhMdYMalapPStHtMAh8BopvBbYPSGvdPvheZChT0mGilTf7RPhdlZfWjX5qBLpAzUrn6tZ/k3XPhFu582f/e5oZb1sIvV4uX3fZmyGSmHnUIn265X7LUhasw6BfnbOACsiGK8IvuOVBnY8XL52UQ5UAmLo10tL3tWnI9y+BBsh4XaSbtiLUE6JMWg+/BRC1hh6bYGtO/6/APsf4LXxKXEafpDG6+ISJC6vist6LbYcelEp4qr2csi7R5EiTsbxSBGf4gejplgeD0Z7CSbyuJN20k7aSTtpJ+2knbSTdtJO+lelrR04VMeepXEJSw9xqris16HAcIQvFsZl2DtI/xoTr7fwmScmlYU8iUNz11qBkN1mbuI4tt2zi7XLOKtXiP2fueR4w6WDzGR6cLIApEML2YLTXrq2c/lZoPoPNtQibDMMVRwAAAAASUVORK5CYII=",
"width": 5,
"height": 5,
"label": "[font-size:10]Dehradun[/]"
}, {
"id": 103,
"minZoomLevel": 3,
"latitude": 26.378494,
"longitude": 80.96383,
"imageURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAAAY1BMVEX///8AAAD39/f19fUmJiYgICAdHR0sLCySkpL8/PwWFhbj4+Px8fEPDw/n5+ecnJw2Nja/v79zc3OKioqlpaW1tbVLS0t/f3/Gxsbd3d3Nzc3X19dUVFRubm6vr69oaGhAQEAk5whvAAAB+klEQVRYhe2Yi5KCIBSGBfGaJqmVabf3f8qVg02GYKgws83wzexOHekP+A+HwPP0aSltFzTXBz9QzwObV67RQG1Y+HJiqkXB/p8uBoVxxSSve8/bX9mrytisNCnTu/M3d/Y6bYwIZ9DRMnm9T0oYQrZdGaY37cahDkZRbBTuIqkKfF/UyT6hSXKGjNhNn+wgY87J9IkeB5iLo/zhEWblsEpYtE9kvZ0x+yCdXR0XytrEC4VbqrWmYfUvqlkZjPWhMdYMalapPStHtMAh8BopvBbYPSGvdPvheZChT0mGilTf7RPhdlZfWjX5qBLpAzUrn6tZ/k3XPhFu582f/e5oZb1sIvV4uX3fZmyGSmHnUIn265X7LUhasw6BfnbOACsiGK8IvuOVBnY8XL52UQ5UAmLo10tL3tWnI9y+BBsh4XaSbtiLUE6JMWg+/BRC1hh6bYGtO/6/APsf4LXxKXEafpDG6+ISJC6vist6LbYcelEp4qr2csi7R5EiTsbxSBGf4gejplgeD0Z7CSbyuJN20k7aSTtpJ+2knbSTdtJO+lelrR04VMeepXEJSw9xqris16HAcIQvFsZl2DtI/xoTr7fwmScmlYU8iUNz11qBkN1mbuI4tt2zi7XLOKtXiP2fueR4w6WDzGR6cLIApEML2YLTXrq2c/lZoPoPNtQibDMMVRwAAAAASUVORK5CYII=",
"width": 5,
"height": 5,
"label": "[font-size:10]Lucknow[/]"
}, {
"id": 104,
"minZoomLevel": 3,
"latitude": 26.378494,
"longitude": 82.96383,
"imageURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAABaCAMAAAAPdrEwAAAAY1BMVEX///8AAAD39/f19fUmJiYgICAdHR0sLCySkpL8/PwWFhbj4+Px8fEPDw/n5+ecnJw2Nja/v79zc3OKioqlpaW1tbVLS0t/f3/Gxsbd3d3Nzc3X19dUVFRubm6vr69oaGhAQEAk5whvAAAB+klEQVRYhe2Yi5KCIBSGBfGaJqmVabf3f8qVg02GYKgws83wzexOHekP+A+HwPP0aSltFzTXBz9QzwObV67RQG1Y+HJiqkXB/p8uBoVxxSSve8/bX9mrytisNCnTu/M3d/Y6bYwIZ9DRMnm9T0oYQrZdGaY37cahDkZRbBTuIqkKfF/UyT6hSXKGjNhNn+wgY87J9IkeB5iLo/zhEWblsEpYtE9kvZ0x+yCdXR0XytrEC4VbqrWmYfUvqlkZjPWhMdYMalapPStHtMAh8BopvBbYPSGvdPvheZChT0mGilTf7RPhdlZfWjX5qBLpAzUrn6tZ/k3XPhFu582f/e5oZb1sIvV4uX3fZmyGSmHnUIn265X7LUhasw6BfnbOACsiGK8IvuOVBnY8XL52UQ5UAmLo10tL3tWnI9y+BBsh4XaSbtiLUE6JMWg+/BRC1hh6bYGtO/6/APsf4LXxKXEafpDG6+ISJC6vist6LbYcelEp4qr2csi7R5EiTsbxSBGf4gejplgeD0Z7CSbyuJN20k7aSTtpJ+2knbSTdtJO+lelrR04VMeepXEJSw9xqris16HAcIQvFsZl2DtI/xoTr7fwmScmlYU8iUNz11qBkN1mbuI4tt2zi7XLOKtXiP2fueR4w6WDzGR6cLIApEML2YLTXrq2c/lZoPoPNtQibDMMVRwAAAAASUVORK5CYII=",
"width": 5,
"height": 5,
"label": "[font-size:10]Dummy[/]"
}];
var hoverState = image.states.create("hover");
hoverState.properties.scale = 1.9;
image.tooltipText = "{label}";
imageSeries.events.on("datavalidated", updateImageVisibility);
chart.events.on("zoomlevelchanged", updateImageVisibility);
function updateImageVisibility(ev) {
var chart = ev.target.baseSprite;
var series = chart.map.getKey("markers");
series.mapImages.each(function(image) {
if (image.dataItem.dataContext.minZoomLevel) {
if (image.dataItem.dataContext.minZoomLevel >= chart.zoomLevel) {
image.hide();
} else {
image.show();
}
}
});
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 100%;
}
.selected {
border: 1px solid red;
border-radius: 5px;
display: inline;
padding-right: 2px;
margin-right: 4px;
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/maps.js"></script>
<script src="https://www.amcharts.com/lib/4/geodata/indiaLow.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="list"></div>
<div id="chartdiv"></div>
It's still not very clear what you're trying to do. When you click an image, what image are you trying to change it to? Why would that affect the zoom level?
I checked out your jsfiddle and instead of zoom level, it's the chart itself shifting up and down because you're populating an element that previously had no height. If you give it a
min-heightthe chart will stop shifting up and down whenever it gains a child for the first time or loses them all.Here's a fork that does that:
Addendum 2019-06-22: Change image on clicking
mapImageTo change the image on click, instead of attempting to update the original data for property field binding, please update the
hrefproperty directly.I.e. instead of:
Just do:
Demo below has been updated to include this, click Uttar Pradesh -> then Meerut (the icon that has a hand/pointer):
https://jsfiddle.net/notacouch/d6u9ofh7/
Addendum 2019-06-26: Change image on clicking "id"
If forking the above, make sure to comment out the image re-assignment line:
ev.target.href = "...";.If you want to change the
mapImage's image when clicking a.selectedelement, I suggest using event delegation on the parent#listdiv to handle their click events, instead of recreating one per new div. Then in that event handler, since you're using jQuery you can check its textual content via.text(), convert that to aNumber, and iterate through themapImagesuntil a matchingmapImage.dataItem.dataContext.idis found. Then assign its child's image.Event handler sample below:
Demo:
https://jsfiddle.net/notacouch/bxgz74t1/
Or instead of iterating, since in this case the
idis the actualidof themapImages, we can useMapImageSeries'getImageById()method:Demo:
https://jsfiddle.net/notacouch/5ravqhoL/