Skip to content

Commit 9739df2

Browse files
committed
observe and map values to named values when match
1 parent cd59cf7 commit 9739df2

3 files changed

Lines changed: 116 additions & 3 deletions

File tree

src/store/conic.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,32 @@ import { writable } from 'svelte/store';
22

33
export const conic_angle = writable('0');
44
export const conic_named_position = writable('center');
5-
export const conic_position = writable({x: null, y: null});
5+
export const conic_position = writable({x: null, y: null});
6+
7+
// Reflect numeric position into named position when it matches a canonical value
8+
function posToName(x: number, y: number): string | null {
9+
const tol = 0
10+
const eq = (a: number, b: number) => Math.abs(a - b) <= tol
11+
if (eq(x,50) && eq(y,50)) return 'center'
12+
if (eq(x,50) && eq(y,0)) return 'top'
13+
if (eq(x,100) && eq(y,50)) return 'right'
14+
if (eq(x,50) && eq(y,100)) return 'bottom'
15+
if (eq(x,0) && eq(y,50)) return 'left'
16+
if (eq(x,100) && eq(y,0)) return 'top right'
17+
if (eq(x,100) && eq(y,100)) return 'bottom right'
18+
if (eq(x,0) && eq(y,100)) return 'bottom left'
19+
if (eq(x,0) && eq(y,0)) return 'top left'
20+
return null
21+
}
22+
23+
let syncing = false
24+
conic_position.subscribe(v => {
25+
if (syncing) return
26+
const x = (v as any)?.x
27+
const y = (v as any)?.y
28+
if (typeof x !== 'number' || typeof y !== 'number') return
29+
const name = posToName(x, y)
30+
syncing = true
31+
try { conic_named_position.set(name ?? '--') }
32+
finally { syncing = false }
33+
})

src/store/linear.ts

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,61 @@
11
import { writable } from 'svelte/store';
22

33
export const linear_named_angle = writable('to right');
4-
export const linear_angle = writable(null);
4+
export const linear_angle = writable(null);
5+
6+
// Keep numeric angle in sync when a named direction is chosen.
7+
// This ensures UI indicators (like the angle icon) reflect the selection.
8+
const nameToDeg: Record<string, number> = {
9+
'to top': 0,
10+
'to top right': 45,
11+
'to right': 90,
12+
'to bottom right': 135,
13+
'to bottom': 180,
14+
'to bottom left': 225,
15+
'to left': 270,
16+
'to top left': 315,
17+
}
18+
19+
let syncing = false
20+
linear_named_angle.subscribe(v => {
21+
if (syncing) return
22+
if (!v || v === '--') return
23+
const deg = nameToDeg[v]
24+
if (typeof deg === 'number') {
25+
syncing = true
26+
try { linear_angle.set(String(deg)) }
27+
finally { syncing = false }
28+
}
29+
})
30+
31+
// When the numeric angle matches a named direction, reflect it in the UI.
32+
linear_angle.subscribe(v => {
33+
if (syncing) return
34+
if (v == null) return
35+
const n = Number(v)
36+
if (Number.isNaN(n)) return
37+
// Normalize to [0,360)
38+
let a = ((n % 360) + 360) % 360
39+
const entries = Object.entries(nameToDeg)
40+
const tol = 0.5
41+
for (const [name, deg] of entries) {
42+
const d = Math.abs((((a - deg) % 360) + 540) % 360 - 180)
43+
if (d <= tol) {
44+
if (name !== 'to bottom' || deg !== 180) {
45+
syncing = true
46+
try { linear_named_angle.set(name) }
47+
finally { syncing = false }
48+
} else {
49+
// default direction; show it explicitly too
50+
syncing = true
51+
try { linear_named_angle.set('to bottom') }
52+
finally { syncing = false }
53+
}
54+
return
55+
}
56+
}
57+
// Not a named angle; show custom
58+
syncing = true
59+
try { linear_named_angle.set('--') }
60+
finally { syncing = false }
61+
})

src/store/radial.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,32 @@ import { writable } from 'svelte/store';
33
export const radial_shape = writable('circle');
44
export const radial_named_position = writable('center');
55
export const radial_position = writable({x: null, y: null});
6-
export const radial_size = writable('farthest-corner');
6+
export const radial_size = writable('farthest-corner');
7+
8+
// Reflect numeric position into named position when it matches a canonical value
9+
function posToName(x: number, y: number): string | null {
10+
const tol = 0 // expect integers from UI/overlay
11+
const eq = (a: number, b: number) => Math.abs(a - b) <= tol
12+
if (eq(x,50) && eq(y,50)) return 'center'
13+
if (eq(x,50) && eq(y,0)) return 'top'
14+
if (eq(x,100) && eq(y,50)) return 'right'
15+
if (eq(x,50) && eq(y,100)) return 'bottom'
16+
if (eq(x,0) && eq(y,50)) return 'left'
17+
if (eq(x,100) && eq(y,0)) return 'top right'
18+
if (eq(x,100) && eq(y,100)) return 'bottom right'
19+
if (eq(x,0) && eq(y,100)) return 'bottom left'
20+
if (eq(x,0) && eq(y,0)) return 'top left'
21+
return null
22+
}
23+
24+
let syncing = false
25+
radial_position.subscribe(v => {
26+
if (syncing) return
27+
const x = (v as any)?.x
28+
const y = (v as any)?.y
29+
if (typeof x !== 'number' || typeof y !== 'number') return
30+
const name = posToName(x, y)
31+
syncing = true
32+
try { radial_named_position.set(name ?? '--') }
33+
finally { syncing = false }
34+
})

0 commit comments

Comments
 (0)