How to Build Ultra-Lightweight, Responsive Image Maps Natively inside Adobe InDesign
The Problem
I use multiple infographics in my publishing work across various websites. You can find an example on MyBibleVersion.com, which provides an infographic to help readers choose a particular Bible version. This infographic is currently built with Adobe InDesign and published using the program’s native “Publish Online” feature.
The advantages of this particular approach include an excellent text layout and graphic creation environment. Creating interactive hotspots is relatively easy as well; you simply draw a shape and assign a hyperlink to it.
There is a distinct disadvantage, however. In order to view the infographic, the reader must manually expand the graphic to read it or follow an external link to a separate page hosted on Adobe’s servers. Having a small infographic that is truly embedded in your local page—while remaining lightweight and responsive—can be incredibly difficult.
I initially attempted to resolve this by creating SVG files using Adobe Illustrator, but the result was very heavy files that frequently triggered security restrictions on my WordPress sites.
Using a standard WordPress Custom HTML block to build an old-school HTML image map could work, but those maps are not dynamically sizable, presenting massive display issues across different mobile device layouts and screen sizes.
I was looking for a modern solution that would allow me to:
- Create infographics in various canvas sizes.
- Embed them cleanly directly into web pages as graphics.
- Allow interactive hotspots to automatically resize as the image is scaled.
- Keep the final file size ultra-lightweight.
- Avoid security warnings or upload blocks.
The Tools
By keeping my workflow inside InDesign, I created a script to convert legacy infographics into this new, lightweight form. To follow along, you need an InDesign layout configured with two specific layers:
- A layer named exactly
Background(housing your main infographic image frame). - A layer named exactly
Hotspots(housing transparent Squares, Circles, or Triangles with native hyperlinks attached via the Hyperlinks panel).
First, load your primary background graphic into a frame on the layer named Background. Your InDesign document pasteboard doesn’t need to be a specific native size, but you want to make sure the frame is correctly proportioned and scaled to make it easy to work with.
Next, switch your active layer to Hotspots. Now you can draw vector shapes over the visual elements of your infographic. For each shape, attach a web URL via the Hyperlinks panel. Do not place any text or graphics inside these hotspot shapes; this script is strictly intended to map interactive vectors, not transfer interior content layers.
For my first example, I used a draft infographic layout generated by NotebookLM (Gemini) based on sources and prompts I provided. It has all the intended graphical elements embedded. You can save your background graphic in any web-friendly format, including JPG, PNG, or WebP.
Once you have drawn all of your hotspot shapes, you are ready to run the script. To find your InDesign scripts directory:
- Go to the top Window menu, select Utilities, then click Scripts.
- In the panel that opens, right-click on the User folder and choose Reveal in Explorer (or Reveal in Finder on Mac).
- This opens the exact directory where your script needs to be saved.
The Complete Code Solution
Open a plain text editor (I use jEdit, but any code editor works fine), copy the code below, and paste it into a new document. Save it in your User scripts folder with the extension .jsx (e.g., infographic_gen.jsx).
JavaScript
// Auto_Export_Infographic_Map.jsx
// An ExtendScript for Adobe InDesign to generate lightweight, responsive SVG hotspots.
(function() {
if (app.documents.length === 0) {
alert("Please open an InDesign document.");
return;
}
var doc = app.activeDocument;
var bgLayer = doc.layers.itemByName("Background");
var hotspotLayer = doc.layers.itemByName("Hotspots");
if (!bgLayer.isValid || !hotspotLayer.isValid) {
alert("Layer Naming Error:\nYour document must have two layers named exactly:\n'Background' and 'Hotspots'");
return;
}
var bgItems = bgLayer.allPageItems;
if (bgItems.length === 0) {
alert("Error: No background frame found inside the 'Background' layer.");
return;
}
var bgFrame = bgItems[0];
var bgBounds = bgFrame.geometricBounds;
var frameY = bgBounds[0];
var frameX = bgBounds[1];
var frameH = bgBounds[2] - bgBounds[0];
var frameW = bgBounds[3] - bgBounds[1];
function getHyperlinkUrl(item) {
for (var h = 0; h < doc.hyperlinks.length; h++) {
var link = doc.hyperlinks[h];
if (link.source.constructor.name === "HyperlinkPageItemSource" && link.source.sourcePageItem === item) {
if (link.destination.constructor.name === "HyperlinkURLDestination") {
return link.destination.destinationURL;
}
}
}
return "https://yourdomain.com/placeholder/";
}
var html = '\n';
html += '<svg viewBox="0 0 ' + frameW.toFixed(2) + ' ' + frameH.toFixed(2) + '" width="100%" height="auto" xmlns="http://www.w3.org/2000/svg">\n';
html += ' <image href="YOUR_IMAGE_URL_HERE.webp" width="' + frameW.toFixed(2) + '" height="' + frameH.toFixed(2) + '" />\n\n';
var hotspots = hotspotLayer.allPageItems;
var validCount = 0;
for (var i = 0; i < hotspots.length; i++) {
var shape = hotspots[i];
var url = getHyperlinkUrl(shape);
var type = shape.constructor.name;
if (type !== "Rectangle" && type !== "Oval" && type !== "Polygon") continue;
validCount++;
html += ' \n';
html += ' <a href="' + url + '" target="_top">\n';
if (type === "Rectangle") {
var bounds = shape.geometricBounds;
var relX = bounds[1] - frameX;
var relY = bounds[0] - frameY;
var relW = bounds[3] - bounds[1];
var relH = bounds[2] - bounds[0];
html += ' <rect x="' + relX.toFixed(2) + '" y="' + relY.toFixed(2) + '" width="' + relW.toFixed(2) + '" height="' + relH.toFixed(2) + '" fill="transparent" style="cursor: pointer;" />\n';
} else if (type === "Oval") {
var bounds = shape.geometricBounds;
var w = bounds[3] - bounds[1];
var h = bounds[2] - bounds[0];
var cx = bounds[1] + (w / 2);
var cy = bounds[0] + (h / 2);
var relCx = cx - frameX;
var relCy = cy - frameY;
var relRx = w / 2;
var relRy = h / 2;
html += ' <ellipse cx="' + relCx.toFixed(2) + '" cy="' + relCy.toFixed(2) + '" rx="' + relRx.toFixed(2) + '" ry="' + relRy.toFixed(2) + '" fill="transparent" style="cursor: pointer;" />\n';
} else if (type === "Polygon") {
var paths = shape.paths.item(0).entirePath;
var pointsString = "";
for (var p = 0; p < paths.length; p++) {
var pt = paths[p];
var relPtX = pt[0] - frameX;
var relPtY = pt[1] - frameY;
pointsString += relPtX.toFixed(2) + "," + relPtY.toFixed(2);
if (p < paths.length - 1) pointsString += " ";
}
html += ' <polygon points="' + pointsString + '" fill="transparent" style="cursor: pointer;" />\n';
}
html += ' </a>\n\n';
}
html += '</svg>';
if (validCount > 0) {
var docQuotes = doc.textPreferences.typographersQuotes;
doc.textPreferences.typographersQuotes = false;
var tempFrame = doc.pages[0].textFrames.add({
geometricBounds: [0, 0, 100, 100],
contents: html
});
tempFrame.parentStory.texts[0].select();
app.copy();
tempFrame.remove();
doc.textPreferences.typographersQuotes = docQuotes;
alert("Automation Complete!\nProcessed " + validCount + " hotspots.\nCode is on your clipboard.");
} else {
alert("No direct shapes detected inside the 'Hotspots' layer.");
}
})();
I collaborated with Gemini to handle the coding logic. While the overall architectural concept and structural math were mine, the ExtendScript compilation was automated. The code is 100% public domain. Feel free to use, modify, or distribute it in any way you want!
The “Under the Hood” Insights (Why It Works)
Some key development challenges resolved by this script include:
- Frame-Relative Coordinates: The script records your hotspots relative to the position and bounding edges of your background image frame rather than the document itself. This means you don’t need to resize your InDesign canvas perfectly every time. Just ensure your graphics and shapes live on their respective layers.
- Typographer’s Quote Safeguard: Getting raw straight programming quotes out of InDesign can be tricky since the program automatically forces curly quotes. The script dynamically overrides typographic settings on the document level during compilation to ensure clean HTML strings.
- The
target="_top"Breakout Rule: Appending this tag parameter to our anchor elements forces links to break out cleanly, commanding the main window to update rather than trapping the destination page inside the narrow viewport boundaries of the infographic.
Converting Legacy Infographics
Since I have a repository of older infographics built traditionally in InDesign, I wanted an easy way to convert them into this high-performance layout format. The transition process is remarkably straightforward, even if your existing vector shapes currently contain text and graphic groupings:
- Export your existing InDesign document layout as a flat, highly compressed image file (JPG, PNG, or WebP). This flat asset becomes your new background.
- Rename your main source layout layer to
Background, and create a new layer stacked directly on top namedHotspots. - Move your existing linked bounding shapes up to the
Hotspotslayer. (Since you exported the background frame as a flat image, the interior graphics and text paths on this overlay layer are no longer needed—they now serve purely as your invisible click targets). - Run the script just like before to generate your responsive code.
Live Examples
- You can find the initial infographic I used to test this script running live at: Navigating Your Spiritual Season
- You can view a converted legacy file running on this automated script architecture at: Energion Publications Web Presence Infographic
Source Files
The following files demonstrate both the basic starter setup and the advanced legacy conversion framework for your own testing:
Download basic starter template (Zip Archive)
Download Advanced Layout Conversion Sample (Zip Archive)