Skip to content

Commit e09e7f6

Browse files
chore: address feedback
1 parent f4f4533 commit e09e7f6

15 files changed

Lines changed: 275 additions & 59 deletions

File tree

src/command/pointerGuidance.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import type { Context } from '@model/context';
2+
import type { AudioService } from '@service/audio';
3+
import type { Command } from './command';
4+
5+
/**
6+
* Command that routes pointer/touch movement into guidance sonification.
7+
*
8+
* This keeps pointer input handling in the command flow rather than
9+
* calling AudioService directly from input-binding services.
10+
*/
11+
export class PointerGuidanceCommand implements Command {
12+
private readonly context: Context;
13+
private readonly audioService: AudioService;
14+
15+
/**
16+
* Creates an instance of PointerGuidanceCommand.
17+
*
18+
* @param context - Application context used for point navigation and guidance lookup
19+
* @param audioService - Audio service that renders guidance beeps
20+
*/
21+
public constructor(context: Context, audioService: AudioService) {
22+
this.context = context;
23+
this.audioService = audioService;
24+
}
25+
26+
/**
27+
* Executes pointer/touch guidance behavior.
28+
*
29+
* If an event with client coordinates is provided, updates nearest point
30+
* navigation and plays directional guidance. If no event is provided,
31+
* guidance is reset (used for pointer leave / unregister).
32+
*
33+
* @param event - Optional pointer/mouse event containing clientX/clientY
34+
*/
35+
public execute(event?: Event): void {
36+
if (!event || !this.hasClientCoordinates(event)) {
37+
this.audioService.playTouchGuidance(null);
38+
return;
39+
}
40+
41+
const { clientX, clientY } = event;
42+
this.context.moveToPoint(clientX, clientY);
43+
44+
const guidance = this.context.getTouchGuidance(clientX, clientY);
45+
this.audioService.playTouchGuidance(guidance);
46+
}
47+
48+
private hasClientCoordinates(
49+
event: Event,
50+
): event is Event & { clientX: number; clientY: number } {
51+
const candidate = event as Partial<{ clientX: unknown; clientY: unknown }>;
52+
return typeof candidate.clientX === 'number' && typeof candidate.clientY === 'number';
53+
}
54+
}

src/model/abstract.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ export interface Dimension {
5050
cols: number;
5151
}
5252

53-
export interface NearestPoint {
53+
interface NearestPoint {
5454
element: SVGElement;
5555
row: number;
5656
col: number;
57+
centerX: number;
58+
centerY: number;
5759
}
5860

5961
export abstract class AbstractPlot<State> implements Movable, Observable<State>, Disposable {
@@ -786,15 +788,11 @@ export abstract class AbstractTrace extends AbstractPlot<TraceState> implements
786788
return null;
787789
}
788790

789-
const bbox = nearest.element.getBoundingClientRect();
790-
const centerX = bbox.x + bbox.width / 2;
791-
const centerY = bbox.y + bbox.height / 2;
792-
793791
return {
794792
onCurve: this.isPointInBounds(x, y, nearest),
795-
distancePx: Math.hypot(centerX - x, centerY - y),
796-
verticalRelation: y < centerY ? 'above' : 'below',
797-
horizontalRelation: x < centerX ? 'left' : 'right',
793+
distancePx: Math.hypot(nearest.centerX - x, nearest.centerY - y),
794+
verticalRelation: y < nearest.centerY ? 'above' : 'below',
795+
horizontalRelation: x < nearest.centerX ? 'left' : 'right',
798796
};
799797
}
800798

src/model/bar.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ export abstract class AbstractBarPlot<T extends BarPoint> extends AbstractTrace
247247
public findNearestPoint(
248248
x: number,
249249
y: number,
250-
): { element: SVGElement; row: number; col: number } | null {
250+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
251251
// we differ from the base implementation (which is to loop through centers and return one),
252252
// as sometimes the closest center is not the bar we clicked on
253253
// so instead, we just do the hard thing and loop through all highlightValues
@@ -284,7 +284,13 @@ export abstract class AbstractBarPlot<T extends BarPoint> extends AbstractTrace
284284
&& y >= bbox.y
285285
&& y <= bbox.y + bbox.height
286286
) {
287-
return { element: targetElement, row, col };
287+
return {
288+
element: targetElement,
289+
row,
290+
col,
291+
centerX: bbox.x + bbox.width / 2,
292+
centerY: bbox.y + bbox.height / 2,
293+
};
288294
}
289295
}
290296
}

src/model/box.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ export class BoxTrace extends AbstractTrace {
496496
public findNearestPoint(
497497
x: number,
498498
y: number,
499-
): { element: SVGElement; row: number; col: number } | null {
499+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
500500
if (!this.highlightCenters) {
501501
return null;
502502
}
@@ -521,6 +521,8 @@ export class BoxTrace extends AbstractTrace {
521521
element: this.highlightCenters[nearestIndex].element,
522522
row: this.highlightCenters[nearestIndex].row,
523523
col: this.highlightCenters[nearestIndex].col,
524+
centerX: this.highlightCenters[nearestIndex].x,
525+
centerY: this.highlightCenters[nearestIndex].y,
524526
};
525527
}
526528

src/model/candlestick.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -999,7 +999,7 @@ export class Candlestick extends AbstractTrace {
999999
public findNearestPoint(
10001000
x: number,
10011001
y: number,
1002-
): { element: SVGElement; row: number; col: number } | null {
1002+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
10031003
// loop through highlightCenters to find nearest point
10041004
if (!this.highlightCenters) {
10051005
return null;
@@ -1025,6 +1025,8 @@ export class Candlestick extends AbstractTrace {
10251025
element: this.highlightCenters[nearestIndex].element,
10261026
row: this.highlightCenters[nearestIndex].row,
10271027
col: this.highlightCenters[nearestIndex].col,
1028+
centerX: this.highlightCenters[nearestIndex].x,
1029+
centerY: this.highlightCenters[nearestIndex].y,
10281030
};
10291031
}
10301032

src/model/heatmap.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ export class Heatmap extends AbstractTrace {
394394
public findNearestPoint(
395395
x: number,
396396
y: number,
397-
): { element: SVGElement; row: number; col: number } | null {
397+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
398398
// loop through highlightCenters to find nearest point
399399
if (!this.highlightCenters) {
400400
return null;
@@ -420,6 +420,8 @@ export class Heatmap extends AbstractTrace {
420420
element: this.highlightCenters[nearestIndex].element,
421421
row: this.highlightCenters[nearestIndex].row,
422422
col: this.highlightCenters[nearestIndex].col,
423+
centerX: this.highlightCenters[nearestIndex].x,
424+
centerY: this.highlightCenters[nearestIndex].y,
423425
};
424426
}
425427

src/model/line.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ export class LineTrace extends AbstractTrace {
766766
public findNearestPoint(
767767
x: number,
768768
y: number,
769-
): { element: SVGElement; row: number; col: number } | null {
769+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
770770
// loop through highlightCenters to find nearest point
771771
if (!this.highlightCenters) {
772772
return null;
@@ -792,6 +792,8 @@ export class LineTrace extends AbstractTrace {
792792
element: this.highlightCenters[nearestIndex].element,
793793
row: this.highlightCenters[nearestIndex].row,
794794
col: this.highlightCenters[nearestIndex].col,
795+
centerX: this.highlightCenters[nearestIndex].x,
796+
centerY: this.highlightCenters[nearestIndex].y,
795797
};
796798
}
797799

src/model/plot.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,7 @@ export interface Trace extends Movable, Observable<TraceState>, Disposable {
601601
* @returns Guidance state or null if unavailable
602602
*/
603603
getTouchGuidance: (x: number, y: number) => TouchGuidanceState | null;
604+
604605
/**
605606
* Gets extrema targets for navigation.
606607
* Optional method implemented by traces that support extrema navigation.

src/model/scatter.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ export class ScatterTrace extends AbstractTrace implements GridNavigable {
11681168
public findNearestPoint(
11691169
_x: number,
11701170
_y: number,
1171-
): { element: SVGElement; row: number; col: number } | null {
1171+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
11721172
// loop through highlightCenters to find nearest point
11731173
if (!this.highlightCenters) {
11741174
return null;
@@ -1194,6 +1194,8 @@ export class ScatterTrace extends AbstractTrace implements GridNavigable {
11941194
element: this.highlightCenters[nearestIndex].element,
11951195
row: this.highlightCenters[nearestIndex].row,
11961196
col: this.highlightCenters[nearestIndex].col,
1197+
centerX: this.highlightCenters[nearestIndex].x,
1198+
centerY: this.highlightCenters[nearestIndex].y,
11971199
};
11981200
}
11991201

src/model/violin.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ export class ViolinKdeTrace extends AbstractTrace {
657657
public findNearestPoint(
658658
x: number,
659659
y: number,
660-
): { element: SVGElement; row: number; col: number } | null {
660+
): { element: SVGElement; row: number; col: number; centerX: number; centerY: number } | null {
661661
if (!this.highlightCenters) {
662662
return null;
663663
}
@@ -682,6 +682,8 @@ export class ViolinKdeTrace extends AbstractTrace {
682682
element: this.highlightCenters[nearestIndex].element,
683683
row: this.highlightCenters[nearestIndex].row,
684684
col: this.highlightCenters[nearestIndex].col,
685+
centerX: this.highlightCenters[nearestIndex].x,
686+
centerY: this.highlightCenters[nearestIndex].y,
685687
};
686688
}
687689

0 commit comments

Comments
 (0)