Why do it?

Labels drawn with the LabelCanvas drawLabel, drawLabelOnPath, and drawLabelInPath methods are rendered as HTML on top of the map. Because they are HTML, a label can contain more than text: you can put links, buttons, or form controls inside a label and let the map user interact with them.

This article explains how input is shared between labels and the map, which label content is interactive out of the box, and how to make your own custom content interactive.

How input is shared between labels and the map

The label layer sits on top of the map. If that layer captured every click and touch, a finger resting on a label would stop the map from panning or zooming, because the touch events would never reach the map.

To avoid this, the label layer is transparent to input by default: it is rendered with pointer-events: none. A click or touch on label text therefore falls through to the map, so panning, zooming, and picking keep working even when the pointer or finger is over a label. This also means LuciadRIA’s own label selection and hovering keep working, because those are driven by the map, not by the label element.

Interactive content inside a label opts back in to receiving input, so a click or touch on a button or input is handled by that element instead of being passed to the map. This is exactly what you want: navigating the map by dragging over label text, but pressing a button when you tap the button.

This behavior applies to both mouse and touch input. On touch devices in particular, it is what allows the map to be panned with a finger that starts on a label.

Interactive content that works automatically

The following native interactive elements receive mouse and touch input automatically when they appear inside a label. You do not have to do anything special:

  • links with an href: <a href="…​">

  • <button>

  • <input>

  • <select>

  • <textarea>

  • <label>

  • elements with a contenteditable attribute

For example, this painter draws a point label containing a button:

import {FeaturePainter} from "@luciad/ria/view/feature/FeaturePainter.js";
import {LabelCanvas} from "@luciad/ria/view/style/LabelCanvas.js";
import {PointLabelPosition} from "@luciad/ria/view/style/PointLabelPosition.js";
import {Feature} from "@luciad/ria/model/feature/Feature.js";
import {Shape} from "@luciad/ria/shape/Shape.js";

class MyPainter extends FeaturePainter {
  paintLabel(labelCanvas: LabelCanvas, feature: Feature, shape: Shape): void {
    const label = document.createElement("div");
    label.innerHTML = `<span>${feature.properties.name}</span>`;

    const button = document.createElement("button");
    button.textContent = "Details";
    button.addEventListener("click", () => showDetails(feature));
    label.appendChild(button);

    labelCanvas.drawLabel(label, shape, {
      positions: PointLabelPosition.NORTH,
      group: "NON_DECLUTTERED"
    });
  }
}

Tapping the button triggers its handler, while dragging on the rest of the label pans the map.

Making custom content interactive

If your interactive element is not one of the native elements listed above, for example a clickable <div> or a custom web component, add the lcd-label-interactive CSS class to it. That class re-enables input on the element while the rest of the label stays transparent to input.

const clickable = document.createElement("div");
clickable.className = "lcd-label-interactive";
clickable.textContent = "Click me";
clickable.addEventListener("click", () => doSomething());
label.appendChild(clickable);

The lcd-label-interactive class is equivalent to setting pointer-events: auto on the element yourself. If you already manage the element’s CSS, you can set that property directly instead of adding the class:

.my-clickable-label-content {
  pointer-events: auto;
}

Keep interactive areas small

Because any element that opts in to input also stops the map from being panned over its area, keep your interactive elements no larger than they need to be. If you make an entire label interactive, the map can no longer be panned by dragging over that label. Prefer attaching interactivity to the specific control (a button or input), and leave surrounding text transparent so the map stays navigable.

If you previously relied on a click handler attached to the whole label element, move the handler to an inner control, or add the lcd-label-interactive class to the element that should be clickable.