Appearance
LabelPlugin
HTML overlay labels attached to 3D objects. Labels are positioned each frame against the active camera, support custom renderers per label type, and can be dragged by the user. Leader lines are drawn in SVG.
Usage
ts
const viewer = new ViewerCore(container, {
plugins: [{ name: "label", enabled: true }],
});
await viewer.ready();
const labels = viewer.pluginManager.getPlugin("label") as LabelPlugin;
labels.registerLabelType("note", (label) => {
const el = document.createElement("div");
el.textContent = label.data?.text ?? "";
return el;
});
const id = labels.addLabel({
type: "note",
targetMeshId: someMesh.userData.xv.xvId,
localPosition: [0, 0, 0],
data: { text: "Bearing housing" },
});Or:
ts
await viewer.loadPlugin(new LabelPlugin());Service dependencies: label, mesh. The plugin creates an HTML overlay layered above the renderer canvas. The parent of the canvas is forced to position: relative if static.
Public API
| Method | Description |
|---|---|
registerLabelType(type, renderer, config?: Partial<LabelTypeConfig>) | Register a label type and its renderer. Existing labels of this type are re-rendered. |
unregisterLabelType(type) | Remove a type and all its visible label instances. |
addLabel(data) | Add a label. Returns the new label id. data omits id, createdAt, updatedAt. |
updateLabel(id, patch) | Patch an existing label. |
removeLabel(id) | Remove a label. |
clearLabels(filter?: LabelFilter) | Bulk remove (passes through to LabelService). |
getLabels(filter?: LabelFilter) | List labels matching the filter. |
| `setVisibleTypes(types: string[] | "all")` |
setFilter(fn | null) | Custom per-label visibility predicate. |
setLabelRenderer(id, renderer | null) | Override the renderer for a single label. |
setLabelStyle(id, style: Partial<LabelStyle>) | Per-label style override (offset, leader line). |
Types
ts
type LabelRenderer = (label: Label) => HTMLElement;
interface LeaderStyle {
color: string;
width: number;
dashArray?: string;
opacity?: number;
}
interface LabelTypeConfig {
renderer: LabelRenderer;
leaderLineStyle?: LeaderStyle;
offset?: [number, number]; // pixel offset from anchor
zIndex?: number;
className?: string; // CSS class on the label root
}
interface LabelStyle {
leaderLineStyle?: LeaderStyle;
offset?: [number, number];
}A Label is owned by LabelService and includes id, type, targetMeshId, localPosition, and arbitrary data. See the service for the full shape.
Default offset is [0, -20]. Default leader is { color: "#0f172a", width: 2, opacity: 0.8 }.
Behaviour notes
- Labels are draggable. The current drag offset is remembered per label until removed; programmatic re-positioning resumes after pointer release.
- Labels are hidden when the anchor falls outside the camera near/far planes.
- Z-index is auto-assigned based on distance from camera.
LabelTypeConfig.zIndexis added on top. - Anchors resolve via
MeshService.getById(label.targetMeshId), falling back to a scene traversal foruserData.xv.xvId.
Example
ts
labels.registerLabelType("part", (label) => {
const el = document.createElement("div");
el.textContent = label.data.partName;
el.style.background = "#0ea5e9";
el.style.color = "white";
el.style.padding = "4px 8px";
el.style.borderRadius = "6px";
return el;
}, {
offset: [12, -24],
leaderLineStyle: { color: "#0ea5e9", width: 2, opacity: 0.9 },
zIndex: 10,
});
const id = labels.addLabel({
type: "part",
targetMeshId: mesh.userData.xv.xvId,
localPosition: [0, 0, 0],
data: { partName: "Housing" },
});
labels.setVisibleTypes(["part"]);