Skip to content

Commit e6437de

Browse files
committed
Reduce duplicate code
1 parent 529d4c4 commit e6437de

1 file changed

Lines changed: 32 additions & 39 deletions

File tree

frontend/src/components/widgets/inputs/RulerInput.svelte

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@
3030
$: isHorizontal = direction === "Horizontal";
3131
$: trackedAxis = isHorizontal ? axes.horiz : axes.vert;
3232
$: otherAxis = isHorizontal ? axes.vert : axes.horiz;
33+
$: otherVec = flipVec(otherAxis.vec, flip);
3334
$: stretchFactor = 1 / Math.max(Math.abs(isHorizontal ? trackedAxis.vec[0] : trackedAxis.vec[1]), 1e-10);
3435
$: stretchedSpacing = majorMarkSpacing * stretchFactor;
35-
$: effectiveOrigin = computeEffectiveOrigin(direction, originX, originY, otherAxis, flip);
36-
$: svgPath = computeSvgPath(direction, effectiveOrigin, stretchedSpacing, stretchFactor, minorDivisions, microDivisions, rulerLength, otherAxis, flip);
37-
$: svgTexts = computeSvgTexts(direction, effectiveOrigin, stretchedSpacing, numberInterval, rulerLength, trackedAxis, otherAxis, tilt);
38-
$: cursorIndicatorPath = computeCursorIndicator(direction, cursorPosition, otherAxis, flip);
36+
$: effectiveOrigin = projectOntoRuler(direction, originX, originY, otherVec);
37+
$: svgPath = computeSvgPath(direction, effectiveOrigin, stretchedSpacing, stretchFactor, minorDivisions, microDivisions, rulerLength, otherVec);
38+
$: svgTexts = computeSvgTexts(direction, effectiveOrigin, stretchedSpacing, numberInterval, rulerLength, trackedAxis, otherAxis.vec, tilt);
39+
$: cursorIndicatorPath = computeCursorIndicator(direction, cursorPosition, otherVec);
3940
4041
function computeAxes(tilt: number): { horiz: Axis; vert: Axis } {
4142
const normTilt = ((tilt % TAU) + TAU) % TAU;
@@ -53,14 +54,24 @@
5354
return { horiz: posY, vert: negX };
5455
}
5556
56-
function computeEffectiveOrigin(direction: RulerDirection, ox: number, oy: number, otherAxis: Axis, flip: boolean): number {
57-
const [rawVx, vy] = otherAxis.vec;
58-
const vx = flip ? -rawVx : rawVx;
59-
if (direction === "Horizontal") {
60-
return Math.abs(vy) < 1e-10 ? ox : ox - oy * (vx / vy);
61-
} else {
62-
return Math.abs(vx) < 1e-10 ? oy : oy - ox * (vy / vx);
63-
}
57+
function flipVec(vec: [number, number], flipped: boolean): [number, number] {
58+
return flipped ? [-vec[0], vec[1]] : vec;
59+
}
60+
61+
function projectOntoRuler(direction: RulerDirection, x: number, y: number, vec: [number, number]): number {
62+
const [vx, vy] = vec;
63+
if (direction === "Horizontal") return Math.abs(vy) < 1e-10 ? x : x - y * (vx / vy);
64+
return Math.abs(vx) < 1e-10 ? y : y - x * (vy / vx);
65+
}
66+
67+
function tickMarkGeometry(direction: RulerDirection, vx: number, vy: number): { dx: number; dy: number; sxBase: number; syBase: number } {
68+
const reversal = direction === "Horizontal" ? (vy > 0 ? -1 : 1) : vx > 0 ? -1 : 1;
69+
return {
70+
dx: vx * reversal,
71+
dy: vy * reversal,
72+
sxBase: direction === "Horizontal" ? 0 : RULER_THICKNESS,
73+
syBase: direction === "Horizontal" ? RULER_THICKNESS : 0,
74+
};
6475
}
6576
6677
function computeSvgPath(
@@ -71,19 +82,14 @@
7182
minorDivisions: number,
7283
microDivisions: number,
7384
rulerLength: number,
74-
otherAxis: Axis,
75-
flip: boolean,
85+
otherVec: [number, number],
7686
): string {
7787
const adaptive = stretchFactor > 1.3 ? { minor: minorDivisions, micro: 1 } : { minor: minorDivisions, micro: microDivisions };
7888
const divisions = stretchedSpacing / adaptive.minor / adaptive.micro;
7989
const majorMarksFrequency = adaptive.minor * adaptive.micro;
8090
const shiftedOffsetStart = mod(effectiveOrigin, stretchedSpacing) - stretchedSpacing;
8191
82-
const [rawVx, vy] = otherAxis.vec;
83-
const vx = flip ? -rawVx : rawVx;
84-
const reversal = direction === "Horizontal" ? (vy > 0 ? -1 : 1) : vx > 0 ? -1 : 1;
85-
const [dx, dy] = [vx * reversal, vy * reversal];
86-
const [sxBase, syBase] = direction === "Horizontal" ? [0, RULER_THICKNESS] : [RULER_THICKNESS, 0];
92+
const { dx, dy, sxBase, syBase } = tickMarkGeometry(direction, otherVec[0], otherVec[1]);
8793
8894
let path = "";
8995
let i = 0;
@@ -109,18 +115,16 @@
109115
numberInterval: number,
110116
rulerLength: number,
111117
trackedAxis: Axis,
112-
otherAxis: Axis,
118+
unflippedOtherVec: [number, number],
113119
tilt: number,
114120
): { transform: string; text: string }[] {
115121
const isVertical = direction === "Vertical";
116122
117-
const [rawVx, vy] = otherAxis.vec;
118-
119123
// Tip offset uses the un-flipped axis so text stays on the correct side of tick marks
120-
const tipReversal = isVertical ? (rawVx > 0 ? -1 : 1) : vy > 0 ? -1 : 1;
124+
const { dx: tipDx, dy: tipDy } = tickMarkGeometry(direction, unflippedOtherVec[0], unflippedOtherVec[1]);
121125
const tiltScale = tilt >= 0 ? 1 : 0.5;
122-
const tipOffsetX = rawVx * tipReversal * MAJOR_MARK_THICKNESS * tiltScale;
123-
const tipOffsetY = vy * tipReversal * MAJOR_MARK_THICKNESS * tiltScale;
126+
const tipOffsetX = tipDx * MAJOR_MARK_THICKNESS * tiltScale;
127+
const tipOffsetY = tipDy * MAJOR_MARK_THICKNESS * tiltScale;
124128
125129
const shiftedOffsetStart = mod(effectiveOrigin, stretchedSpacing) - stretchedSpacing;
126130
const increments = Math.round((shiftedOffsetStart - effectiveOrigin) / stretchedSpacing);
@@ -147,22 +151,11 @@
147151
return results;
148152
}
149153
150-
function computeCursorIndicator(direction: RulerDirection, cursor: { x: number; y: number } | undefined, otherAxis: Axis, flip: boolean): string {
154+
function computeCursorIndicator(direction: RulerDirection, cursor: { x: number; y: number } | undefined, otherVec: [number, number]): string {
151155
if (cursor === undefined) return "";
152156
153-
// Project cursor position along the other axis onto the ruler strip
154-
const [rawVx, vy] = otherAxis.vec;
155-
const vx = flip ? -rawVx : rawVx;
156-
let projected: number;
157-
if (direction === "Horizontal") {
158-
projected = Math.abs(vy) < 1e-10 ? cursor.x : cursor.x - cursor.y * (vx / vy);
159-
} else {
160-
projected = Math.abs(vx) < 1e-10 ? cursor.y : cursor.y - cursor.x * (vy / vx);
161-
}
162-
163-
const reversal = direction === "Horizontal" ? (vy > 0 ? -1 : 1) : vx > 0 ? -1 : 1;
164-
const [dx, dy] = [vx * reversal, vy * reversal];
165-
const [sxBase, syBase] = direction === "Horizontal" ? [0, RULER_THICKNESS] : [RULER_THICKNESS, 0];
157+
const projected = projectOntoRuler(direction, cursor.x, cursor.y, otherVec);
158+
const { dx, dy, sxBase, syBase } = tickMarkGeometry(direction, otherVec[0], otherVec[1]);
166159
167160
// Scale the line so it spans the full ruler bar thickness
168161
const thicknessComponent = Math.abs(direction === "Horizontal" ? dy : dx);

0 commit comments

Comments
 (0)