I have an existing image map in a responsive html layout. Images scale according to browser size, but the image coordinates are obviously fixed pixel sizes. What options do I have to resize the image map coordinates?
For responsive image maps you will need to use a plugin:
https://github.com/stowball/jQuery-rwdImageMaps (No longer maintained)
Or
https://github.com/davidjbradshaw/imagemap-resizer
No major browsers understand percentage coordinates correctly, and all interpret percentage coordinates as pixel coordinates.
http://www.howtocreate.co.uk/tutorials/html/imagemaps
And also this page for testing whether browsers implement
You can also use SVG instead of an image map. There is a tutorial on how to do this. Sample below, imported from this jsfiddle.
.hover_group:hover {
opacity: 1;
}
#projectsvg {
position: relative;
width: 100%;
padding-bottom: 77%;
vertical-align: middle;
margin: 0;
overflow: hidden;
background: lightgreen;
}
#projectsvg svg {
display: inline-block;
position: absolute;
top: 0;
left: 0;
}
<figure id="projectsvg">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1920 1080" preserveAspectRatio="xMinYMin meet">
<!-- set your background image -->
<image width="1920" height="1080" xlink:href="http://placehold.it/1920x1080" />
<!-- create the regions -->
<g class="hover_group" opacity="0">
<a xlink:href="https://example.com/link1.html">
<text x="652" y="706.9" font-size="20">First zone</text>
<rect x="572" y="324.1" opacity="0.2" fill="#FFFFFF" width="264.6" height="387.8"></rect>
</a>
</g>
<g class="hover_group" opacity="0">
<a xlink:href="https://example.com/link2.html">
<text x="1230.7" y="952" font-size="20">Second zone</text>
<rect x="1081.7" y="507" opacity="0.2" fill="#FFFFFF" width="390.2" height="450"></rect>
</a>
</g>
</svg>
</figure>
I found a no-JS way to address this. The hit areas will be rectangular unless you change the border-radius to make circular or oval areas.
First of all, make sure your image is in a div that's relatively positioned. Then put the image inside this div, which means it'll take up all the space in the div. Finally, add absolutely positioned div's under the image, within the main div, and use percentages for top, left, width, and height to get the link hit areas the size and position you want.
I find it's easiest to give the div a black background color (ideally with some alpha fading so you can see the linked content underneath) when you're first working, and to use a code inspector in your browser to adjust the percentages in real time, so that you can get it just right.
Here's the basic outline you can work with. By doing everything with percentages, you ensure the elements all stay the same relative size and position as the image scales.
<div style="position: relative;">
<img src="background-image.png" style="width: 100%; height: auto;">
<a href="/link1"><div style="position: absolute; left: 15%; top: 20%; width: 12%; height: 8%; background-color: rgba(0, 0, 0, .25);"></div></a>
<a href="/link2"><div style="position: absolute; left: 52%; top: 38%; width: 14%; height: 20%; background-color: rgba(0, 0, 0, .25);"></div></a>
</div>
Use this code with your code inspector in Chrome or your browser of choice, and adjust the percentages (you can use decimal percentages to be more exact) until the boxes are just right. Also choose a background-color
of transparent
when you're ready to use it since you want your hit areas to be invisible.
Responsive Image Maps jQuery Plugin by Matt Stow
$(window).trigger('resize');
–
Unnecessary window
in this case). Good luck. –
Unnecessary I ran across a solution that doesn't use image maps at all but rather anchor tags that are absolutely positioned over the image. The only drawback would be that the hotspot would have to be rectangular, but the plus is that this solution doesn't rely on Javascript, just CSS. There is a website that you can use to generate the HTML code for the anchors: http://www.zaneray.com/responsive-image-map/
I put the image and the generated anchor tags in a relatively positioned div tag and everything worked perfectly on window resize and on my mobile phone.
The following method works perfectly for me, so here's my full implementation:
<img id="my_image" style="display: none;" src="my.png" width="924" height="330" border="0" usemap="#map" />
<map name="map" id="map">
<area shape="poly" coords="774,49,810,21,922,130,920,222,894,212,885,156,874,146" href="#mylink" />
<area shape="poly" coords="649,20,791,157,805,160,809,217,851,214,847,135,709,1,666,3" href="#myotherlink" />
</map>
<script>
$(function(){
var image_is_loaded = false;
$("#my_image").on('load',function() {
$(this).data('width', $(this).attr('width')).data('height', $(this).attr('height'));
$($(this).attr('usemap')+" area").each(function(){
$(this).data('coords', $(this).attr('coords'));
});
$(this).css('width', '100%').css('height','auto').show();
image_is_loaded = true;
$(window).trigger('resize');
});
function ratioCoords (coords, ratio) {
coord_arr = coords.split(",");
for(i=0; i < coord_arr.length; i++) {
coord_arr[i] = Math.round(ratio * coord_arr[i]);
}
return coord_arr.join(',');
}
$(window).on('resize', function(){
if (image_is_loaded) {
var img = $("#my_image");
var ratio = img.width()/img.data('width');
$(img.attr('usemap')+" area").each(function(){
console.log('1: '+$(this).attr('coords'));
$(this).attr('coords', ratioCoords($(this).data('coords'), ratio));
});
}
});
});
</script>
David Bradshaw wrote a nice little library that solves this problem. It can be used with or without jQuery.
Available here: https://github.com/davidjbradshaw/imagemap-resizer
consider to use this image mapper
https://imagemapper.noc.io/#/ | github | alternative link
its SVG based and its responsive and
it have good wizards to build the map
its simple enough for the page because it use no library
Working for me (remember to change 3 things in code):
previousWidth (original size of image)
map_ID (id of your image map)
img_ID (id of your image)
HTML:
<div style="width:100%;">
<img id="img_ID" src="http://www.gravatar.com/avatar/0865e7bad648eab23c7d4a843144de48?s=128&d=identicon&r=PG" usemap="#map" border="0" width="100%" alt="" />
</div>
<map id="map_ID" name="map">
<area shape="poly" coords="48,10,80,10,65,42" href="javascript:;" alt="Bandcamp" title="Bandcamp" />
<area shape="poly" coords="30,50,62,50,46,82" href="javascript:;" alt="Facebook" title="Facebook" />
<area shape="poly" coords="66,50,98,50,82,82" href="javascript:;" alt="Soundcloud" title="Soundcloud" />
</map>
Javascript:
window.onload = function () {
var ImageMap = function (map, img) {
var n,
areas = map.getElementsByTagName('area'),
len = areas.length,
coords = [],
previousWidth = 128;
for (n = 0; n < len; n++) {
coords[n] = areas[n].coords.split(',');
}
this.resize = function () {
var n, m, clen,
x = img.offsetWidth / previousWidth;
for (n = 0; n < len; n++) {
clen = coords[n].length;
for (m = 0; m < clen; m++) {
coords[n][m] *= x;
}
areas[n].coords = coords[n].join(',');
}
previousWidth = img.offsetWidth;
return true;
};
window.onresize = this.resize;
},
imageMap = new ImageMap(document.getElementById('map_ID'), document.getElementById('img_ID'));
imageMap.resize();
return;
}
JSFiddle: http://jsfiddle.net/p7EyT/154/
I come across with same requirement where, I wants to show responsive image map which can resize with any screen size and important thing is, i want to highlight that coordinates.
So i tried many libraries which can resize coordinates according to screen size and event. And i got best solution(jquery.imagemapster.min.js) which works fine with almost all browsers. Also i have integrated it with Summer Plgin which create image map.
var resizeTime = 100;
var resizeDelay = 100;
$('img').mapster({
areas: [
{
key: 'tbl',
fillColor: 'ff0000',
staticState: true,
stroke: true
}
],
mapKey: 'state'
});
// Resize the map to fit within the boundaries provided
function resize(maxWidth, maxHeight) {
var image = $('img'),
imgWidth = image.width(),
imgHeight = image.height(),
newWidth = 0,
newHeight = 0;
if (imgWidth / maxWidth > imgHeight / maxHeight) {
newWidth = maxWidth;
} else {
newHeight = maxHeight;
}
image.mapster('resize', newWidth, newHeight, resizeTime);
}
function onWindowResize() {
var curWidth = $(window).width(),
curHeight = $(window).height(),
checking = false;
if (checking) {
return;
}
checking = true;
window.setTimeout(function () {
var newWidth = $(window).width(),
newHeight = $(window).height();
if (newWidth === curWidth &&
newHeight === curHeight) {
resize(newWidth, newHeight);
}
checking = false;
}, resizeDelay);
}
$(window).bind('resize', onWindowResize);
img[usemap] {
border: none;
height: auto;
max-width: 100%;
width: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.imagemapster.min.js"></script>
<img src="https://discover.luxury/wp-content/uploads/2016/11/Cities-With-the-Most-Michelin-Star-Restaurants-1024x581.jpg" alt="" usemap="#map" />
<map name="map">
<area shape="poly" coords="777, 219, 707, 309, 750, 395, 847, 431, 916, 378, 923, 295, 870, 220" href="#" alt="poly" title="Polygon" data-maphilight='' state="tbl"/>
<area shape="circle" coords="548, 317, 72" href="#" alt="circle" title="Circle" data-maphilight='' state="tbl"/>
<area shape="rect" coords="182, 283, 398, 385" href="#" alt="rect" title="Rectangle" data-maphilight='' state="tbl"/>
</map>
Hope help it to someone.
For those who don't want to resort to JavaScript, here's an image slicing example:
http://codepen.io/anon/pen/cbzrK
As you scale the window, the clown image will scale accordingly, and when it does, the nose of the clown remains hyperlinked.
It depends, you can use jQuery to adjust the ranges proportionally I think. Why do you use an image map by the way? Can't you use scaling divs or other elements for it?
Similar to Orland's answer here: https://mcmap.net/q/36849/-maintain-the-aspect-ratio-of-a-div-with-css
Combined with Chris' code here: https://mcmap.net/q/76136/-responsively-change-div-size-keeping-aspect-ratio-duplicate
If the areas fit in a grid you can overlay the areas by transparent pictures using a width in % that keep their aspect ratio.
.wrapperspace {
width: 100%;
display: inline-block;
position: relative;
}
.mainspace {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
<div class="wrapperspace">
<img style="float: left;" title="" src="background-image.png" width="100%" />
<div class="mainspace">
<div>
<img src="space-top.png" style="margin-left:6%;width:15%;"/>
</div>
<div>
<a href="http://www.example.com"><img src="space-company.png" style="margin-left:6%;width:15%;"></a>
</div>
<div>
<a href="http://www.example.com"><img src="space-company.png" style="margin-left:6%;width:10%;"></a>
<a href="http://www.example.com"><img src="space-company.png" style="width:20%;"></a>
</div>
</div>
</div>
You can use a margin in %. Additionally "space" images can be placed next to each other inside a 3rd level div.
For some reason none of these solutions worked for me. I've had the best success using transforms.
transform: translateX(-5.8%) translateY(-5%) scale(0.884);
I have created a javascript version of the solution Tom Bisciglia suggested.
My code allows you to use a normal image map. All you have to do is load a few lines of CSS and a few lines of JS and... BOOM... your image map has hover states and is fully responsive! Magic right?
var images = document.querySelectorAll('img[usemap]');
images.forEach( function(image) {
var mapid = image.getAttribute('usemap').substr(1);
var imagewidth = image.getAttribute('width');
var imageheight = image.getAttribute('height');
var imagemap = document.querySelector('map[name="'+mapid+'"]');
var areas = imagemap.querySelectorAll('area');
image.removeAttribute('usemap');
imagemap.remove();
// create wrapper container
var wrapper = document.createElement('div');
wrapper.classList.add('imagemap');
image.parentNode.insertBefore(wrapper, image);
wrapper.appendChild(image);
areas.forEach( function(area) {
var coords = area.getAttribute('coords').split(',');
var xcoords = [parseInt(coords[0]),parseInt(coords[2])];
var ycoords = [parseInt(coords[1]),parseInt(coords[3])];
xcoords = xcoords.sort(function(a, b){return a-b});
ycoords = ycoords.sort(function(a, b){return a-b});
wrapper.innerHTML += "<a href='"+area.getAttribute('href')+"' title='"+area.getAttribute('title')+"' class='area' style='left: "+((xcoords[0]/imagewidth)*100).toFixed(2)+"%; top: "+((ycoords[0]/imageheight)*100).toFixed(2)+"%; width: "+(((xcoords[1] - xcoords[0])/imagewidth)*100).toFixed(2)+"%; height: "+(((ycoords[1] - ycoords[0])/imageheight)*100).toFixed(2)+"%;'></a>";
});
});
img {max-width: 100%; height: auto;}
.imagemap {position: relative;}
.imagemap img {display: block;}
.imagemap .area {display: block; position: absolute; transition: box-shadow 0.15s ease-in-out;}
.imagemap .area:hover {box-shadow: 0px 0px 1vw rgba(0,0,0,0.5);}
<!-- Image Map Generated by http://www.image-map.net/ -->
<img src="https://i.imgur.com/TwmCyCX.jpg" width="2000" height="2604" usemap="#image-map">
<map name="image-map">
<area target="" alt="Zirconia Abutment" title="Zirconia Abutment" href="/" coords="3,12,199,371" shape="rect">
<area target="" alt="Gold Abutment" title="Gold Abutment" href="/" coords="245,12,522,371" shape="rect">
<area target="" alt="CCM Abutment" title="CCM Abutment" href="/" coords="564,12,854,369" shape="rect">
<area target="" alt="EZ Post Abutment" title="EZ Post Abutment" href="/" coords="1036,12,1360,369" shape="rect">
<area target="" alt="Milling Abutment" title="Milling Abutment" href="/" coords="1390,12,1688,369" shape="rect">
<area target="" alt="Angled Abutment" title="Angled Abutment" href="/" coords="1690,12,1996,371" shape="rect">
<area target="" alt="Temporary Abutment [Metal]" title="Temporary Abutment [Metal]" href="/" coords="45,461,506,816" shape="rect">
<area target="" alt="Fuse Abutment" title="Fuse Abutment" href="/" coords="1356,461,1821,816" shape="rect">
<area target="" alt="Lab Analog" title="Lab Analog" href="/" coords="718,935,1119,1256" shape="rect">
<area target="" alt="Transfer Impression Coping Driver" title="Transfer Impression Coping Driver" href="/" coords="8,1330,284,1731" shape="rect">
<area target="" alt="Impression Coping [Transfer]" title="Impression Coping [Transfer]" href="/" coords="310,1330,697,1731" shape="rect">
<area target="" alt="Impression Coping [Pick-Up]" title="Impression Coping [Pick-Up]" href="/" coords="1116,1330,1560,1733" shape="rect">
</map>
var images = document.querySelectorAll('img[usemap]');
images.forEach( function(image) {
var mapid = image.getAttribute('usemap').substr(1);
var imagewidth = image.getAttribute('width');
var imageheight = image.getAttribute('height');
var imagemap = document.querySelector('map[name="'+mapid+'"]');
var areas = imagemap.querySelectorAll('area');
image.removeAttribute('usemap');
imagemap.remove();
// create wrapper container
var wrapper = document.createElement('div');
wrapper.classList.add('imagemap');
image.parentNode.insertBefore(wrapper, image);
wrapper.appendChild(image);
areas.forEach( function(area) {
var coords = area.getAttribute('coords').split(',');
var xcoords = [parseInt(coords[0]),parseInt(coords[2])];
var ycoords = [parseInt(coords[1]),parseInt(coords[3])];
xcoords = xcoords.sort(function(a, b){return a-b});
ycoords = ycoords.sort(function(a, b){return a-b});
wrapper.innerHTML += "<a href='"+area.getAttribute('href')+"' title='"+area.getAttribute('title')+"' class='area' style='left: "+((xcoords[0]/imagewidth)*100).toFixed(2)+"%; top: "+((ycoords[0]/imageheight)*100).toFixed(2)+"%; width: "+(((xcoords[1] - xcoords[0])/imagewidth)*100).toFixed(2)+"%; height: "+(((ycoords[1] - ycoords[0])/imageheight)*100).toFixed(2)+"%;'></a>";
});
});
img {max-width: 100%; height: auto;}
.imagemap {position: relative;}
.imagemap img {display: block;}
.imagemap .area {display: block; position: absolute; transition: box-shadow 0.15s ease-in-out;}
.imagemap .area:hover {box-shadow: 0px 0px 1vw rgba(0,0,0,0.5);}
<!-- Image Map Generated by http://www.image-map.net/ -->
<img src="https://i.imgur.com/TwmCyCX.jpg" width="2000" height="2604" usemap="#image-map">
<map name="image-map">
<area target="" alt="Zirconia Abutment" title="Zirconia Abutment" href="/" coords="3,12,199,371" shape="rect">
<area target="" alt="Gold Abutment" title="Gold Abutment" href="/" coords="245,12,522,371" shape="rect">
<area target="" alt="CCM Abutment" title="CCM Abutment" href="/" coords="564,12,854,369" shape="rect">
<area target="" alt="EZ Post Abutment" title="EZ Post Abutment" href="/" coords="1036,12,1360,369" shape="rect">
<area target="" alt="Milling Abutment" title="Milling Abutment" href="/" coords="1390,12,1688,369" shape="rect">
<area target="" alt="Angled Abutment" title="Angled Abutment" href="/" coords="1690,12,1996,371" shape="rect">
<area target="" alt="Temporary Abutment [Metal]" title="Temporary Abutment [Metal]" href="/" coords="45,461,506,816" shape="rect">
<area target="" alt="Fuse Abutment" title="Fuse Abutment" href="/" coords="1356,461,1821,816" shape="rect">
<area target="" alt="Lab Analog" title="Lab Analog" href="/" coords="718,935,1119,1256" shape="rect">
<area target="" alt="Transfer Impression Coping Driver" title="Transfer Impression Coping Driver" href="/" coords="8,1330,284,1731" shape="rect">
<area target="" alt="Impression Coping [Transfer]" title="Impression Coping [Transfer]" href="/" coords="310,1330,697,1731" shape="rect">
<area target="" alt="Impression Coping [Pick-Up]" title="Impression Coping [Pick-Up]" href="/" coords="1116,1330,1560,1733" shape="rect">
</map>
responsive width && height
window.onload = function() {
var ImageMap = function(map, img) {
var n,
areas = map.getElementsByTagName('area'),
len = areas.length,
coords = [],
imgWidth = img.naturalWidth,
imgHeight = img.naturalHeight;
for (n = 0; n < len; n++) {
coords[n] = areas[n].coords.split(',');
}
this.resize = function() {
var n, m, clen,
x = img.offsetWidth / imgWidth,
y = img.offsetHeight / imgHeight;
imgWidth = img.offsetWidth;
imgHeight = img.offsetHeight;
for (n = 0; n < len; n++) {
clen = coords[n].length;
for (m = 0; m < clen; m += 2) {
coords[n][m] *= x;
coords[n][m + 1] *= y;
}
areas[n].coords = coords[n].join(',');
}
return true;
};
window.onresize = this.resize;
},
imageMap = new ImageMap(document.getElementById('map_region'), document.getElementById('prepay_region'));
imageMap.resize();
return;
}
© 2022 - 2024 — McMap. All rights reserved.