diff options
| author | skal <pascal.massimino@gmail.com> | 2026-02-06 22:53:29 +0100 |
|---|---|---|
| committer | skal <pascal.massimino@gmail.com> | 2026-02-06 22:53:29 +0100 |
| commit | 0c98c830b382d66c420524ff395e12164a566dd8 (patch) | |
| tree | dc80376bd0f0a492b7a74037ae84a926af18bf15 /tools/editor/sdf.js | |
| parent | 64145080cddbc0fe9fec7159e9ffdedca48ae9be (diff) | |
feat(spectral_editor): Add cursor-centered zoom and pan with mouse wheel
Implemented zoom and pan system for the spectral editor:
Core Features:
- Viewport offset system (viewportOffsetX, viewportOffsetY) for panning
- Three wheel interaction modes:
* Ctrl/Cmd + wheel: Cursor-centered zoom (both axes)
* Shift + wheel: Horizontal pan
* Normal wheel: Vertical pan
- Zoom range: 0.5-20.0x horizontal, 0.1-5.0x vertical
- Zoom factor: 0.9/1.1 per wheel notch (10% change)
Technical Implementation:
- Calculate data position under cursor before zoom
- Apply zoom to pixelsPerFrame and pixelsPerBin
- Adjust viewport offsets to keep cursor position stable
- Clamp offsets to valid ranges (0 to max content size)
- Updated all coordinate conversion functions (screenToSpectrogram, spectrogramToScreen)
- Updated playhead rendering with visibility check
- Reset viewport offsets on file load
Algorithm (cursor-centered zoom):
1. Calculate frame and frequency under cursor: pos = (screen + offset) / scale
2. Apply zoom: scale *= zoomFactor
3. Adjust offset: offset = pos * scale - screen
4. Clamp offset to [0, maxOffset]
This matches the zoom behavior of the timeline editor, adapted for 2D spectrogram display.
handoff(Claude): Spectral editor zoom implementation complete
Diffstat (limited to 'tools/editor/sdf.js')
| -rw-r--r-- | tools/editor/sdf.js | 39 |
1 files changed, 0 insertions, 39 deletions
diff --git a/tools/editor/sdf.js b/tools/editor/sdf.js deleted file mode 100644 index c68d79a..0000000 --- a/tools/editor/sdf.js +++ /dev/null @@ -1,39 +0,0 @@ -// --- Signed Distance Functions (SDFs) --- -// Generic 2D vector operations -function vec2(x, y) { return { x: x, y: y }; } -function length(v) { return Math.sqrt(v.x * v.x + v.y * v.y); } -function dot(v1, v2) { return v1.x * v2.x + v1.y * v2.y; } -function sub(v1, v2) { return vec2(v1.x - v2.x, v1.y - v2.y); } -function mul(v, s) { return vec2(v.x * s, v.y * s); } -function div(v, s) { return vec2(v.x / s, v.y / s); } -function normalize(v) { return div(v, length(v)); } -function clamp(x, minVal, maxVal) { return Math.max(minVal, Math.min(x, maxVal)); } -function abs(v) { return vec2(Math.abs(v.x), Math.abs(v.y)); } -function max(v1, v2) { return vec2(Math.max(v1.x, v2.x), Math.max(v1.y, v2.y)); } -function sign(x) { return (x > 0) ? 1 : ((x < 0) ? -1 : 0); } - -// sdSegment(p, a, b) - signed distance to a line segment -// p: point, a: segment start, b: segment end -function sdSegment(p, a, b) { - const pa = sub(p, a); - const ba = sub(b, a); - const h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); - return length(sub(pa, mul(ba, h))); -} - -// sdEllipse(p, r) - signed distance to an ellipse (p relative to center, r is half-extents) -// p: point relative to ellipse center, r: half-extents (rx, ry) -function sdEllipse(p, r) { - const k0 = vec2(1, length(div(p, r))); - const k1 = vec2(length(div(p, r)), 1); - const f = ((dot(div(mul(p, p), k0), vec2(1, 1)) < dot(div(mul(p, p), k1), vec2(1, 1))) ? k0 : k1); - return length(sub(p, mul(r, normalize(mul(f, p))))) * sign(length(p) - r.x); // Simplified, original has length(p)-r.x which is only for circular -} - -// sdBox(p, r) - signed distance to a rectangle (p relative to center, r is half-extents) -// p: point relative to box center, r: half-extents (hx, hy) -function sdBox(p, r) { - const q = sub(abs(p), r); - return length(max(q, vec2(0, 0))) + Math.min(0.0, Math.max(q.x, q.y)); -} - |
