Skip to content

ImageMapster: draw the regions as SVG, drop jQuery and the library - #16

Merged
oblomov-dev merged 1 commit into
mainfrom
claude/custom-controls-batches-libraries-vqtvpj
Aug 10, 2026
Merged

oblomov-dev merged 1 commit into
mainfrom
claude/custom-controls-batches-libraries-vqtvpj

Conversation

@oblomov-dev

Copy link
Copy Markdown
Member

Why

jquery.imagemapster drew the highlights on a <canvas>, and it is a jQuery plugin — its whole API is $.fn.mapster. That made this control the only thing in the entire stack pulling jQuery in (the abap2UI5 frontend uses none), it needed a 41 kB library from a CDN or vendored into the BSP, and it cost the control a running fight that was documented in the old source:

  • mapster fired onClick before applying its own toggle, so reading the selection back reported it one click behind
  • the canvas had to be re-measured by hand, from a ResizeObserver calling mapster("resize")
  • a re-render patched the <img> in place, leaving the old binding live on it, so binding again silently reset mapster's selection while the canvas stayed painted

What changed

An SVG overlay has none of that. viewBox is the image's natural pixel space — the same space the HTML image map coords are written in — so the browser scales the shapes with the image and there is nothing to observe or re-measure.

before after
scaling ResizeObserver + mapster("resize") viewBox, by the browser
rendering rasterised canvas vectors, sharp at any zoom
click state reported one click behind ours, cannot lag
keyboard <area href="#"> focusable shapes with role and label
dependencies jQuery + 41 kB library none

The ABAP contract is unchanged

Same types, same fields, same sample. Three knobs are now no-ops, kept in place because removing an optional parameter or a structure field breaks the compile of every caller that uses it: liburl and autoresize on render( ), and scale_map in ty_s_config. All three described the old engine's mechanics — there is no library to point at and nothing to resize. Marked IGNORED in the ABAP Doc and in the README.

Testing

The arithmetic — image map coords → SVG geometry, and the config/state/area layering that resolves what a region is painted with — is split into cc/MapShapes.js so it can be tested without a browser. tools/map-shapes.test.mjs covers it along with the selection logic (18 cases).

Geometry cannot be tested that way, so tools/overlay-check.html drives the control in headless Chromium and asserts that the overlay sits on the image, that a click at a point in the picture lands on the region drawn there, and that both still hold after a resize. 27 checks, wired into CI as npm run check:browser, no npm package involved — it finds a Chromium or skips itself.

It earned its place immediately: it caught that the overlay's alignment depends on the image being width: 100% inside the frame, and that my comment claiming the frame "shrink-wraps the image" was wrong — a block box never shrinks to its child's width. The renderer now states the real invariant instead.

Side effects

imagemapster leaves package.json and tools/libs.json, so the local branch is one library and 41 kB lighter, and the control works without internet on main too. The overview app lists it as needing no library.

Verified

abaplint 0 issues (70 files; 85 in the local build), 27 unit tests, 27 browser checks, app2bsp and vendor in sync, local build still green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HJz2xJiGdXe7fGyVrtFFzA


Generated by Claude Code

jquery.imagemapster drew the highlights on a canvas, and it is a jQuery plugin
- its whole API is $.fn.mapster. That made this control the only thing in the
entire stack pulling jQuery in (the abap2UI5 frontend uses none), it needed a
41 kB library from a CDN or vendored into the BSP, and it cost the control a
running fight that is documented in the old source: mapster fired onClick
BEFORE applying its own toggle, so reading the selection back reported it one
click behind; the canvas had to be re-measured by hand from a ResizeObserver
calling mapster("resize"); and a re-render patched the <img> in place, leaving
the old binding live on it so binding again silently reset mapster's selection
while the canvas stayed painted.

An SVG overlay has none of that. viewBox is the image's natural pixel space -
the same space the HTML image map coords are written in - so the browser scales
the shapes with the image and there is nothing to observe or re-measure. Hover
and selection are ordinary DOM events, so the state is ours and cannot lag. The
shapes are vectors rather than a rasterised canvas, so they stay sharp when the
page is zoomed, and each one is a real focusable element with a role and a
label instead of an <area href="#">, which is what makes the map keyboard
reachable at all.

The ABAP contract is unchanged - same types, same fields, same sample. Three
knobs are now no-ops, kept in place because removing an optional parameter or a
structure field breaks the compile of every caller that uses it: `liburl` and
`autoresize` on render( ), and `scale_map` in ty_s_config. All three described
the old engine's mechanics; there is no library to point at and nothing to
resize. They are marked IGNORED in the ABAP Doc and in the README.

The arithmetic - image map coords to SVG geometry, and the config/state/area
layering that resolves what a region is painted with - is split into
cc/MapShapes.js so it can be tested without a browser, and tools/map-shapes.test.mjs
covers it along with the selection logic (18 cases).

What that cannot cover is geometry, so tools/overlay-check.html drives the
control in headless Chromium and asserts that the overlay sits on the image,
that a click at a point in the picture lands on the region drawn there, and
that both still hold after a resize - 27 checks, wired into CI as
`npm run check:browser`, no npm package involved. It earned its place
immediately: it caught that the overlay's alignment depends on the image being
`width: 100%` inside the frame, and that the comment claiming the frame
"shrink-wraps the image" was wrong, since a block box never shrinks to its
child's width. The renderer now states the real invariant.

imagemapster leaves package.json and tools/libs.json, so the local branch is
one library and 41 kB lighter, and the control works without internet on `main`
too. The overview app lists it as needing no library.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJz2xJiGdXe7fGyVrtFFzA
Copilot AI lite review requested due to automatic review settings August 10, 2026 19:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@oblomov-dev
oblomov-dev merged commit c4d86ba into main Aug 10, 2026
4 checks passed
@oblomov-dev
oblomov-dev deleted the claude/custom-controls-batches-libraries-vqtvpj branch August 10, 2026 21:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants