ef-transform-handles
Resize and drag handles for a selected canvas element.
Renders an outlined bounding box with corner/edge resize handles and an optional rotation handle, positioned at bounds. Fires bounds-change on every drag or resize move. pointer-events: none on the host — only the handles themselves capture input.
Consumes panZoomTransformContext to correctly map pointer coordinates when the canvas is panned or zoomed.
<ef-timegroup id="demo" mode="fixed" duration="5s" class="w-[1920px] h-[1080px] bg-slate-900 flex items-center justify-center">
<style>
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.08); }
}
.demo-text { animation: pulse 2.4s ease-in-out infinite; display: inline-block; }
</style>
<ef-text class="demo-text text-white text-7xl font-bold">Hello</ef-text>
</ef-timegroup>
<ef-controls target="demo">
<div class="th-chrome">
<ef-toggle-play>
<button slot="play" class="th-btn">▶</button>
<button slot="pause" class="th-btn">⏸</button>
</ef-toggle-play>
<span class="th-hint">ef-transform-handles wraps a canvas element to enable resize and drag</span>
</div>
</ef-controls>
<style>
.th-chrome {
display: flex;
align-items: center;
gap: 12px;
padding: 8px 16px;
border-top: 1px solid rgba(255,255,255,0.08);
}
.th-btn { cursor: pointer; padding: 4px 10px; font-size: 13px; }
.th-hint { font-size: 11px; opacity: 0.4; }
</style>Typical usage inside an ef-overlay-layer:
<ef-overlay-layer>
<ef-overlay-item element-id="my-text">
<ef-transform-handles
enable-rotation
enable-resize
canvas-scale="1"
></ef-transform-handles>
</ef-overlay-item>
</ef-overlay-layer>
Events:
| Event | Detail | Description |
|---|---|---|
bounds-change | { bounds: TransformBounds } | Fires on every drag/resize move |
rotation-change | { rotation: number } | Fires during rotation drag |
Interaction modifiers:
| Key | Behavior |
|---|---|
Shift | Lock aspect ratio during resize |
Ctrl / Meta | Resize from center |