-
Notifications
You must be signed in to change notification settings - Fork 264
Description
Labels Canvas Not Created When Labels Provided After Mount
Environment
- Platform: Electron application
- Component:
EmbeddingViewfrom@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 2Attempted Workarounds (all unsuccessful):
- ✗ Using
level: 0, priority: 0to ensure labels visible at base zoom - ✗ Using coordinates from actual data range instead of normalized 0-1
- ✗ Forcing component remount with
keyprop when data loads - ✗ Using
useMemoto ensure stable label array reference - ✗ Passing labels from initial render (empty array → populated array)
- ✗ 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:
- Create the label canvas lazily when labels are first provided (not just at mount)
- 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
- Lazy canvas creation: Modify
labels.tsto create the label canvas when labels are first provided, not just during initial mount - Lifecycle hook: Add logic to detect when labels transition from empty/null to populated and initialize canvas at that point
- 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.