Skip to content

Commit 2019704

Browse files
committed
fix: address review feedback for Range editor
1 parent b95636f commit 2019704

8 files changed

Lines changed: 68 additions & 133 deletions

File tree

src/components/range/RangeEditor.vue

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,11 @@ import { useRangeEditor } from '@/composables/useRangeEditor'
178178
import type { ColorStop } from '@/lib/litegraph/src/interfaces'
179179
import type { RangeValue } from '@/lib/litegraph/src/types/widgets'
180180
181-
import {
182-
clamp,
183-
gammaToPosition,
184-
normalize,
185-
positionToGamma
186-
} from './rangeUtils'
181+
import { normalize } from '@/utils/mathUtil'
182+
183+
import { clamp } from 'es-toolkit'
184+
185+
import { gammaToPosition, positionToGamma } from './rangeUtils'
187186
188187
const {
189188
display = 'plain',
@@ -214,7 +213,8 @@ const { handleTrackPointerDown, startDrag } = useRangeEditor({
214213
trackRef,
215214
modelValue,
216215
valueMin: toRef(() => valueMin),
217-
valueMax: toRef(() => valueMax)
216+
valueMax: toRef(() => valueMax),
217+
showMidpoint: toRef(() => showMidpoint)
218218
})
219219
220220
function onTrackPointerDown(e: PointerEvent) {

src/components/range/WidgetRange.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<RangeEditor
3-
:model-value="effectiveValue.value"
3+
:model-value="effectiveValue"
44
:display="widget?.options?.display"
55
:gradient-stops="widget?.options?.gradient_stops"
66
:show-midpoint="widget?.options?.show_midpoint"
@@ -64,8 +64,8 @@ watch(upstreamValue, (upstream) => {
6464
6565
const effectiveValue = computed(() =>
6666
isDisabled.value && upstreamValue.value
67-
? { value: upstreamValue.value }
68-
: { value: modelValue.value }
67+
? upstreamValue.value
68+
: modelValue.value
6969
)
7070
7171
function onValueChange(value: RangeValue) {

src/components/range/rangeUtils.test.ts

Lines changed: 1 addition & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,6 @@
11
import { describe, expect, it } from 'vitest'
22

3-
import {
4-
constrainRange,
5-
denormalize,
6-
formatMidpointLabel,
7-
gammaToPosition,
8-
isRangeValue,
9-
normalize,
10-
positionToGamma
11-
} from './rangeUtils'
12-
13-
describe('normalize', () => {
14-
it('normalizes value to 0-1', () => {
15-
expect(normalize(128, 0, 256)).toBe(0.5)
16-
expect(normalize(0, 0, 255)).toBe(0)
17-
expect(normalize(255, 0, 255)).toBe(1)
18-
})
19-
20-
it('returns 0 when min equals max', () => {
21-
expect(normalize(5, 5, 5)).toBe(0)
22-
})
23-
})
24-
25-
describe('denormalize', () => {
26-
it('converts normalized value back to range', () => {
27-
expect(denormalize(0.5, 0, 256)).toBe(128)
28-
expect(denormalize(0, 0, 255)).toBe(0)
29-
expect(denormalize(1, 0, 255)).toBe(255)
30-
})
31-
32-
it('round-trips with normalize', () => {
33-
expect(denormalize(normalize(100, 0, 255), 0, 255)).toBeCloseTo(100)
34-
})
35-
})
3+
import { gammaToPosition, isRangeValue, positionToGamma } from './rangeUtils'
364

375
describe('positionToGamma', () => {
386
it('converts 0.5 to gamma 1.0', () => {
@@ -60,51 +28,6 @@ describe('gammaToPosition', () => {
6028
})
6129
})
6230

63-
describe('formatMidpointLabel', () => {
64-
it('formats linear scale as decimal', () => {
65-
expect(formatMidpointLabel(0.5, 'linear')).toBe('0.50')
66-
})
67-
68-
it('formats gamma scale as gamma value', () => {
69-
expect(formatMidpointLabel(0.5, 'gamma')).toBe('1.00')
70-
})
71-
})
72-
73-
describe('constrainRange', () => {
74-
it('passes through valid range unchanged', () => {
75-
const result = constrainRange({ min: 0.2, max: 0.8 })
76-
expect(result).toEqual({ min: 0.2, max: 0.8, midpoint: undefined })
77-
})
78-
79-
it('clamps values to default [0, 1]', () => {
80-
const result = constrainRange({ min: -0.5, max: 1.5 })
81-
expect(result.min).toBe(0)
82-
expect(result.max).toBe(1)
83-
})
84-
85-
it('clamps values to custom range', () => {
86-
const result = constrainRange({ min: -10, max: 300 }, 0, 255)
87-
expect(result.min).toBe(0)
88-
expect(result.max).toBe(255)
89-
})
90-
91-
it('enforces min <= max', () => {
92-
const result = constrainRange({ min: 0.8, max: 0.3 })
93-
expect(result.min).toBe(0.8)
94-
expect(result.max).toBe(0.8)
95-
})
96-
97-
it('preserves midpoint when present', () => {
98-
const result = constrainRange({ min: 0.2, max: 0.8, midpoint: 0.5 })
99-
expect(result.midpoint).toBe(0.5)
100-
})
101-
102-
it('clamps midpoint to [0, 1]', () => {
103-
const result = constrainRange({ min: 0.2, max: 0.8, midpoint: 1.5 })
104-
expect(result.midpoint).toBe(1)
105-
})
106-
})
107-
10831
describe('isRangeValue', () => {
10932
it('returns true for valid range', () => {
11033
expect(isRangeValue({ min: 0, max: 1 })).toBe(true)

src/components/range/rangeUtils.ts

Lines changed: 1 addition & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,8 @@ import { clamp } from 'es-toolkit'
22

33
import type { RangeValue } from '@/lib/litegraph/src/types/widgets'
44

5-
export { clamp }
6-
7-
export function normalize(value: number, min: number, max: number): number {
8-
return max === min ? 0 : (value - min) / (max - min)
9-
}
10-
11-
export function denormalize(
12-
normalized: number,
13-
min: number,
14-
max: number
15-
): number {
16-
return min + normalized * (max - min)
17-
}
18-
195
export function positionToGamma(position: number): number {
6+
// Avoid log2(0) = -Infinity and log2(1) = 0 (division by zero in gamma)
207
const clamped = clamp(position, 0.001, 0.999)
218
return -Math.log2(clamped)
229
}
@@ -25,28 +12,6 @@ export function gammaToPosition(gamma: number): number {
2512
return Math.pow(2, -gamma)
2613
}
2714

28-
export function formatMidpointLabel(
29-
position: number,
30-
scale: 'linear' | 'gamma'
31-
): string {
32-
if (scale === 'gamma') {
33-
return positionToGamma(position).toFixed(2)
34-
}
35-
return position.toFixed(2)
36-
}
37-
38-
export function constrainRange(
39-
value: RangeValue,
40-
valueMin: number = 0,
41-
valueMax: number = 1
42-
): RangeValue {
43-
const min = clamp(value.min, valueMin, valueMax)
44-
const max = clamp(Math.max(min, value.max), valueMin, valueMax)
45-
const midpoint =
46-
value.midpoint !== undefined ? clamp(value.midpoint, 0, 1) : undefined
47-
return { min, max, midpoint }
48-
}
49-
5015
export function isRangeValue(value: unknown): value is RangeValue {
5116
if (typeof value !== 'object' || value === null || Array.isArray(value))
5217
return false

src/composables/useRangeEditor.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { Ref } from 'vue'
33

44
import { clamp } from 'es-toolkit'
55

6-
import { denormalize, normalize } from '@/components/range/rangeUtils'
6+
import { denormalize, normalize } from '@/utils/mathUtil'
77
import type { RangeValue } from '@/lib/litegraph/src/types/widgets'
88

99
type HandleType = 'min' | 'max' | 'midpoint'
@@ -13,13 +13,15 @@ interface UseRangeEditorOptions {
1313
modelValue: Ref<RangeValue>
1414
valueMin: Ref<number>
1515
valueMax: Ref<number>
16+
showMidpoint: Ref<boolean>
1617
}
1718

1819
export function useRangeEditor({
1920
trackRef,
2021
modelValue,
2122
valueMin,
22-
valueMax
23+
valueMax,
24+
showMidpoint
2325
}: UseRangeEditorOptions) {
2426
const activeHandle = ref<HandleType | null>(null)
2527
let cleanupDrag: (() => void) | null = null
@@ -28,10 +30,7 @@ export function useRangeEditor({
2830
const el = trackRef.value
2931
if (!el) return valueMin.value
3032
const rect = el.getBoundingClientRect()
31-
const normalized = Math.max(
32-
0,
33-
Math.min(1, (e.clientX - rect.left) / rect.width)
34-
)
33+
const normalized = clamp((e.clientX - rect.left) / rect.width, 0, 1)
3534
return denormalize(normalized, valueMin.value, valueMax.value)
3635
}
3736

@@ -41,7 +40,7 @@ export function useRangeEditor({
4140
const dMax = Math.abs(value - max)
4241
let best: HandleType = dMin <= dMax ? 'min' : 'max'
4342
const bestDist = Math.min(dMin, dMax)
44-
if (midpoint !== undefined) {
43+
if (midpoint !== undefined && showMidpoint.value) {
4544
const midAbs = min + midpoint * (max - min)
4645
if (Math.abs(value - midAbs) < bestDist) {
4746
best = 'midpoint'

src/lib/litegraph/src/types/widgets.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,6 @@ export interface IWidgetRangeOptions extends IWidgetOptions {
355355
midpoint_scale?: 'linear' | 'gamma'
356356
value_min?: number
357357
value_max?: number
358-
histogram?: Uint32Array | null
359358
}
360359

361360
export interface IRangeWidget extends IBaseWidget<

src/utils/mathUtil.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,39 @@
11
import { describe, expect, it } from 'vitest'
22

33
import type { ReadOnlyRect } from '@/lib/litegraph/src/interfaces'
4-
import { computeUnionBounds, gcd, lcm } from '@/utils/mathUtil'
4+
import {
5+
computeUnionBounds,
6+
denormalize,
7+
gcd,
8+
lcm,
9+
normalize
10+
} from '@/utils/mathUtil'
511

612
describe('mathUtil', () => {
13+
describe('normalize', () => {
14+
it('normalizes value to 0-1', () => {
15+
expect(normalize(128, 0, 256)).toBe(0.5)
16+
expect(normalize(0, 0, 255)).toBe(0)
17+
expect(normalize(255, 0, 255)).toBe(1)
18+
})
19+
20+
it('returns 0 when min equals max', () => {
21+
expect(normalize(5, 5, 5)).toBe(0)
22+
})
23+
})
24+
25+
describe('denormalize', () => {
26+
it('converts normalized value back to range', () => {
27+
expect(denormalize(0.5, 0, 256)).toBe(128)
28+
expect(denormalize(0, 0, 255)).toBe(0)
29+
expect(denormalize(1, 0, 255)).toBe(255)
30+
})
31+
32+
it('round-trips with normalize', () => {
33+
expect(denormalize(normalize(100, 0, 255), 0, 255)).toBeCloseTo(100)
34+
})
35+
})
36+
737
describe('gcd', () => {
838
it('should compute greatest common divisor correctly', () => {
939
expect(gcd(48, 18)).toBe(6)

src/utils/mathUtil.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,23 @@
11
import type { ReadOnlyRect } from '@/lib/litegraph/src/interfaces'
2+
3+
/**
4+
* Linearly maps a value from [min, max] to [0, 1].
5+
* Returns 0 when min equals max to avoid division by zero.
6+
*/
7+
export function normalize(value: number, min: number, max: number): number {
8+
return max === min ? 0 : (value - min) / (max - min)
9+
}
10+
11+
/**
12+
* Linearly maps a normalized value from [0, 1] back to [min, max].
13+
*/
14+
export function denormalize(
15+
normalized: number,
16+
min: number,
17+
max: number
18+
): number {
19+
return min + normalized * (max - min)
20+
}
221
import type { Bounds } from '@/renderer/core/layout/types'
322

423
/** Simple 2D point or size as [x, y] or [width, height] */

0 commit comments

Comments
 (0)