Skip to content

Labels Canvas Not Created When Labels Provided After Mount #141

@ted-dunstone

Description

@ted-dunstone

Labels Canvas Not Created When Labels Provided After Mount

Environment

  • Platform: Electron application
  • Component: EmbeddingView from @apple/embedding-atlas
  • React Version: "react": "^19.2.0",
  • Library Version: "embedding-atlas": "^0.15.0"

Description

Labels are not rendering in EmbeddingView. After investigation, the label canvas element is never created, even when labels are properly passed to the component.

Expected Behavior

When passing a valid labels prop to EmbeddingView, a second canvas element should be created to render the labels, and labels should be visible on the embedding visualization.

Actual Behavior

Only one canvas element is created (the main embedding canvas). The label canvas is never initialized, and consequently no labels are rendered.

Steps to Reproduce

import { EmbeddingView } from '@apple/embedding-atlas';

const testLabels = [
  {x: -5.2, y: -1.8, text: 'TEST LABEL', level: 0, priority: 0},
  {x: 0, y: 0, text: 'CENTER', level: 0, priority: 0}
];

function MyComponent() {
  const [xColumn, setXColumn] = useState(null);
  const [yColumn, setYColumn] = useState(null);
  
  // ... data loading logic that populates xColumn and yColumn
  
  return (
    <EmbeddingView
      width={800}
      height={600}
      data={{
        x: xColumn,
        y: yColumn,
        category: categoryColumn
      }}
      labels={testLabels}
      // ... other props
    />
  );
}

Data range for reference:

  • X range: -6.537 to 0.152
  • Y range: -3.184 to 3.678
  • Label coordinates are within these ranges

Investigation

Looking at the source code in labels.ts, the label canvas appears to be created only during component initialization. When inspecting the DOM:

const canvases = document.querySelectorAll('canvas');
console.log('Canvas count:', canvases.length); // Returns 1, should be 2

Attempted Workarounds (all unsuccessful):

  1. ✗ Using level: 0, priority: 0 to ensure labels visible at base zoom
  2. ✗ Using coordinates from actual data range instead of normalized 0-1
  3. ✗ Forcing component remount with key prop when data loads
  4. ✗ Using useMemo to ensure stable label array reference
  5. ✗ Passing labels from initial render (empty array → populated array)
  6. ✗ Trying various label coordinate positions

Root Cause Hypothesis

Based on code review of labels.ts, the label canvas creation appears to be tied to component initialization. If labels are null, undefined, or an empty array during mount, the canvas is never created - even when labels are provided in subsequent renders.

The component may need to:

  1. Create the label canvas lazily when labels are first provided (not just at mount)
  2. Or handle the case where labels transition from null/empty to populated

Electron-Specific Considerations

This issue is occurring in an Electron environment. While unlikely, there could be Electron-specific rendering quirks related to:

  • Canvas creation timing
  • WebGL context initialization
  • DOM manipulation in Electron's rendering process

Proposed Solutions

  1. Lazy canvas creation: Modify labels.ts to create the label canvas when labels are first provided, not just during initial mount
  2. Lifecycle hook: Add logic to detect when labels transition from empty/null to populated and initialize canvas at that point
  3. Documentation: If labels must be provided at mount time, document this requirement clearly

Additional Context

  • Main embedding visualization works perfectly (points render correctly)
  • All other EmbeddingView features work as expected
  • Only the labels feature is affected

Note: This affects use cases where embedding data is loaded asynchronously (common in real applications), as labels cannot be provided until the data coordinate ranges are known.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions