Are HTML Image Maps Still Used

Are HTML Image Maps still used?

Yes, people do still use image maps. An alternative would be to position elements using absolute positioning and CSS but that's not necessarily better. It also doesn't allow you to have shapes like in image maps

Are image maps (html tag - map) crawled by google?

I've been wondering this recently too and found this within the Google developer instructions around enterprise site search - https://developers.google.com/search-appliance/documentation/68/admin_crawl/Introduction#areatag

This suggests that the Google Search Appliance crawler will not follow these links. Whether that is also true for regular Googlebot I don't know but it would seem likely...

More modern image maps?

Responsive SVG solution or classic image map

After taking Paulie_D's comment about SVG into account, I wrote an alternative using SVG to the classic image map. Both work fine, but the SVG version clearly wins when it comes to responsiveness. Both versions have a connection between the anchors and the respective tooltip using the href-attribute. Both solutions work with vanilla JavaScript, without an extra library.


SVG version

Advantages

  • responsive
  • tooltips can be placed easily using JavaScript

HTML

<svg id="map" version="1.1" viewBox="0 0 300 300">
<image width="300" height="300" xlink:href="http://placehold.it/300"/>

<a xlink:href="#t_1">
<rect x="50" y="50" width="50" height="50" />
</a>

<a xlink:href="#t_2">
<rect x="150" y="150" width="50" height="50" />
</a>
</svg>

<div class="t" id="t_1">Tooltip 1</div>
<div class="t" id="t_2">Tooltip 2</div>

CSS

html, body {
width: 100%;
margin: 0;
padding: 0;
}

svg {
display: block;
width: 80%;
max-width: 300px;
margin: 0 auto;
}

svg rect {
fill: white;
opacity: 0.1;
transition: all 0.2s linear;
}

svg rect:hover {
opacity: 0.8;
}

.t {
opacity: 0;
position: absolute;
left: 0;
top: 0;
transition: opacity 0.4s linear;
}

.t.active {
opacity: 1;
}

JavaScript*

var map = document.getElementById('map');
var areas = map.getElementsByTagName('a');
var offset = { left: 30, top: 70 };

for (var i = 0; i < areas.length; i++) {
areas[i].onmouseover = function() {
// get child element
var c = this.firstElementChild;
// get tooltip
var t = document.getElementById(this.getAttribute('xlink:href').substr(1));
// set styles
t.style.left = (map.offsetLeft + parseInt(c.getAttribute('x')) + offset.left) + 'px';
t.style.top = (map.offsetTop + parseInt(c.getAttribute('y')) + offset.top) + 'px';
// show it
t.classList.toggle('active');
}
areas[i].onmouseout = function() {
// get tooltip
var t = document.getElementById(this.getAttribute('xlink:href').substr(1));
// hide it
t.classList.toggle('active');
}
}

Notes

  • the positioning could be improved, it's just to show a direction

Demo

Try before buy


Classic image map version

HTML

<img src="http://placehold.it/300" alt="Sample Image" usemap="#map">
<map id="map" name="map">
<area shape="rect" coords="0,0,50,50" href="#t_1" alt="Tip 1" data-left="80px" data-top="80px" />
<area shape="rect" coords="100,100,150,150" href="#t_2" alt="Tip 2" data-left="180px" data-top="180px" />
</map>

<div class="t" id="t_1">Tooltip 1</div>
<div class="t" id="t_2">Tooltip 2</div>

CSS

.t {
opacity: 0;
position: absolute;
left: 0;
top: 0;
transition: opacity 0.4s linear;
}

.t.active {
opacity: 1;
}

JavaScript*

var areas = document.getElementById('map').children;

for (var i = 0; i < areas.length; i++) {
areas[i].onmouseover = function() {
var t = document.getElementById(this.hash.substr(1));
t.style.left = this.dataset.left;
t.style.top = this.dataset.top;
t.classList.toggle('active');
}
areas[i].onmouseout = function() {
var t = document.getElementById(this.hash.substr(1));
t.classList.toggle('active');
}
}

Notes

  • attaching the position using the data-*-attributes, decouples the JavaScript (unfortunately you can't use offsetLeft/Top and determine the position based on the area-element) - you could however calculate it by using the coords-attribute
  • the JavaScript code could be improved (for example store tooltips instead of re-query them all the time)

Demo

Try before buy



* In both examples the JavaScript could be improved, e.g. store tooltip elements in a variable instead of re-query them all the time.

Image maps and HTML5

Why is using image maps for navigation inexcusable? It's a tool like any other; it has a time and place. Using imagemaps with javascript enhancements is backward compatible, degrades gracefully, and has 100% browser support. They don't need a plugin like flash.They've been supported practically since the dawn of the web browser. Just because something's old doesn't mean it isn't useful; quite the opposite, it means it's well supported.

I wrote a jquery plugin called ImageMapster to add effects to imagemaps so you could create interactive images without using flash. It would be easy to implement a tool that had the same functonality without Javascript support by replacing with a list in those cases. Personally, I think trying to write for the web without javascript is like trying to drive a car without tires. 99% of the web doesn't work without it any more. This isn't 1995. But if you really are concerned, the nice thing about imagemaps is the basic navigation functionality still works. There's no way to accomplish that just with CSS -- not even CSS3 if you have irregular shaped areas.

Is it possible to use HTML image maps within an A-Frame scene?

The <map> tag places the areas above an image. It won't project the areas onto a three dimentional object just like that.

I'd recommend an approach where you re-use the areas defined in the <map> tag within an a-frame custom component.

tldr:

I've made a component that seems to do the job, and is fairly simple in use:

<a-image material="src: #texture" asourcemap="#some-map"></a-image>
<!-- somewhere else -->
<map id="some-map">
<area shape="rect" alt="rectangle" coords="0,0, 50,50" href="rect.html">
<area shape="polygon" alt="poly" coords="0,0, 40,50, 25,0">
</map>

It should work well with the href attribute, but also the <a-image> will emit a signal with the clicked area name.

You can see it working with 3D planes and cylinders here.

end of tldr

0. Gathering <map> data

Simple parsing. Grab the <map> element, iterate through all children, and collect their data with getAttribute():

var map = document.querySelector(selector);
for (let area of map.children) {
// area.getAttribute("href") - href attribute
// area.getAttribute("alt") - alt name
// area.getAttribute("coords") - coordinates array.
}

Store them for later use. The coordinates are comma separated strings, so you may need to parseInt() them, manage the order (i.e. [[x1,x1], [x2,y2], [x3, y3]])

1. Make the a-frame entity interactable

React on clicks, and what's more important - check where the click occurred:

this.el.addEventListener("click", evt => {
var UVPoint = evt.detail.intersection.uv
})

UV mapping will help us determine which point on the texture was clicked. The UV ranges from <0, 1>, so we will need to re-scale the UVPoint:

// may need waiting for "model-loaded"
let mesh = this.el.getObject3D("mesh")
// this may not be available immidiately
let image = mesh.material.map.image
let x_on_image = UVPoint * image.width
// the y axis goes from <1, 0>
let y_on_image = image.height - UVPoint * image.heigth

So hey, we got the area coordinates and the point coordinates!
There is only one thing left:

2. Determining if an area was clicked

No need to re-invent the wheel here. This SO question on checking if a point is inside a polygon has a simple inside(point, polygon) function. Actually we have everything we need, so the last thing we do is:

  • iterate through the polygons
  • check if the clicked point is inside any of the polygons
  • if positive - do your thing

like this:

var point = [x_on_texture, y_on_texture]
for (var i = 0; i < polygons.length; i++) {
// polygons need to be [[x1, y1], [x2, y2],...[xn, yn]] here
if (inside(point, polygons[i]) {
console.log("polygon", i, "clicked!")
}
}

If you skipped the tldr section - the above steps are combined in this component and used in this example

3. Old, hacky try

Another way of doing this could be:

  • receive a click on the a-frame entity
  • grab the clicked coordinates like in 1
  • hide the scene
  • check out which <area> is at the coordinates with document.elementFromPoint(x, y);.
  • show the scene
  • create a mouse event with document.createEvent("MouseEvent");
  • dispatch it on the <area> element.

The hide / show trick works really good even on my mobile phone. I was really surprised that the scene wasn't flickering, freezing, even slowing down.

But document.elementFromPoint(x, y); didn't work with firefox, and probably any attempt to make it work would be way more time consuming than the 0-2 steps. Also I believe the trappings would become bigger and case-dependant.

Anyway, here's the old-answer component:

/* SETUP
<a-scene>
<a-image press-map>
</a-scene>

<image id="image" sourcemap="map">
<map name="map">
<area ...>
</map>
*/

AFRAME.registerComponent("press-map", {
init: function() {
// the underlying image
this.img = document.querySelector("#image")
// react on clicks
this.el.addEventListener("click", evt => {
// get the point on the UV
let uvPoint = evt.detail.intersection.uv
// the y is inverted
let pointOnImage = {
x: uvPoint.x * this.img.width,
y: this.img.height - uvPoint.y * this.img.height
}

// the ugly show-hide bits
this.el.sceneEl.style.display = "none";
this.img.style.display = "block";
// !! grab the <area> at the (x,y) position
var el = document.elementFromPoint(pointOnImage.x, pointOnImage.y);
this.el.sceneEl.style.display="block"
this.img.style.display="none"

// create and dispatch the event
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent(
"click",
true /* bubble */, false /* cancelable */,
window, null,
x, y, 0, 0, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
el.dispatchEvent(ev);
}
}
})

HTML Image Maps - Is there an easy way to create and modify them?

Many program do this. It is to time consuming doing complicated maps manually.
I know coffeecup is a used tool for this.



Related Topics



Leave a reply



Submit