Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/screen-name/view/AutoTrackerNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ export class AutoTrackerNode extends Node {
const hitArea = new Rectangle( 0, 0, VIDEO_W, VIDEO_H, {
fill: 'transparent',
cursor: 'crosshair',
tagName: 'div',
accessibleName: 'Video tracking area — drag to select object to track',
} );
this.addChild( hitArea );

Expand Down
29 changes: 14 additions & 15 deletions src/screen-name/view/CalibrationToolNode.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Circle, DragListener, HBox, Line, Node, Text } from "scenerystack/scenery";
import { Circle, HBox, Line, Node, RichDragListener, Text } from "scenerystack/scenery";
import { Keypad, PhetFont } from "scenerystack/scenery-phet";
import { KeypadDialog } from "scenerystack/sim";
import { Range, Vector2 } from "scenerystack/dot";
import { Range, type Vector2 } from "scenerystack/dot";
import { DerivedProperty, NumberProperty, Property, type TReadOnlyProperty } from "scenerystack/axon";
import { ComboBox, type ComboBoxItem, Panel, TextPushButton } from "scenerystack/sun";
import { Tandem } from "scenerystack/tandem";
Expand Down Expand Up @@ -43,14 +43,17 @@ export class CalibrationToolNode extends Node {
this.addChild( calibrationLine );

// ── Endpoint circles ──────────────────────────────────────────────────
const makeEndpoint = () => new Circle( ENDPOINT_RADIUS, {
const makeEndpoint = ( accessibleName: string ) => new Circle( ENDPOINT_RADIUS, {
fill: TrackLabColors.calibrationFillProperty,
stroke: TrackLabColors.textOnDarkProperty,
lineWidth: 1.5,
cursor: 'crosshair',
tagName: 'div',
focusable: true,
accessibleName: accessibleName,
} );
const endpoint1 = makeEndpoint();
const endpoint2 = makeEndpoint();
const endpoint1 = makeEndpoint( 'Calibration Point 1' );
const endpoint2 = makeEndpoint( 'Calibration Point 2' );
this.addChild( endpoint1 );
this.addChild( endpoint2 );

Expand Down Expand Up @@ -135,17 +138,13 @@ export class CalibrationToolNode extends Node {

// ── Drag listeners for endpoints ──────────────────────────────────────
const makeDragListener = ( pointProperty: Property<Vector2> ) => {
let startPos = pointProperty.value.copy();
let startPtr = new Vector2( 0, 0 );
return new DragListener( {
start: ( event ) => {
startPos = pointProperty.value.copy();
startPtr = this.globalToLocalPoint( event.pointer.point );
},
drag: ( event ) => {
const ptr = this.globalToLocalPoint( event.pointer.point );
pointProperty.value = startPos.plus( ptr.minus( startPtr ) );
return new RichDragListener( {
positionProperty: pointProperty,
keyboardDragListenerOptions: {
dragSpeed: 200,
shiftDragSpeed: 40,
},
tandem: Tandem.OPT_OUT,
} );
};
endpoint1.addInputListener( makeDragListener( this.point1Property ) );
Expand Down
52 changes: 34 additions & 18 deletions src/screen-name/view/CoordinateSystemNode.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Circle, DragListener, Node, Text } from "scenerystack/scenery";
import { Circle, Node, RichDragListener, Text } from "scenerystack/scenery";
import { ArrowNode, PhetFont } from "scenerystack/scenery-phet";
import { Vector2 } from "scenerystack/dot";
import type { Vector2 } from "scenerystack/dot";
import { NumberProperty, Property, type TReadOnlyProperty } from "scenerystack/axon";
import { Tandem } from "scenerystack/tandem";
import TrackLabColors from "../../TrackLabColors.js";

const ARROW_LENGTH = 120;
Expand Down Expand Up @@ -61,6 +62,9 @@ export class CoordinateSystemNode extends Node {
stroke: TrackLabColors.textOnDarkProperty,
lineWidth: 1.5,
cursor: 'crosshair',
tagName: 'div',
focusable: true,
accessibleName: 'Rotation Handle',
} );
rotatingNode.addChild( handleDisk );

Expand All @@ -72,36 +76,48 @@ export class CoordinateSystemNode extends Node {
} );

// ── Position wrapper: translates with viewPositionProperty ───────────
const positionNode = new Node( { children: [ rotatingNode, originMarker ], cursor: 'move' } );
const positionNode = new Node( {
children: [ rotatingNode, originMarker ],
cursor: 'move',
tagName: 'div',
focusable: true,
accessibleName: 'Coordinate System',
} );
this.addChild( positionNode );

// ── Property → scene-graph linkage ────────────────────────────────────
this.viewPositionProperty.link( pos => { positionNode.translation = pos; } );
this.rotationAngleProperty.link( angle => { rotatingNode.rotation = angle; } );

// ── Drag: translate the entire coordinate system ──────────────────────
let startPos = initialPosition.copy();
let startPtr = new Vector2( 0, 0 );

positionNode.addInputListener( new DragListener( {
start: ( event ) => {
startPos = this.viewPositionProperty.value.copy();
startPtr = this.globalToLocalPoint( event.pointer.point );
},
drag: ( event ) => {
const ptr = this.globalToLocalPoint( event.pointer.point );
this.viewPositionProperty.value = startPos.plus( ptr.minus( startPtr ) );
positionNode.addInputListener( new RichDragListener( {
positionProperty: this.viewPositionProperty,
keyboardDragListenerOptions: {
dragSpeed: 300,
shiftDragSpeed: 50,
},
tandem: Tandem.OPT_OUT,
} ) );

// ── Drag: rotate around origin ────────────────────────────────────────
// Dragging the handle disk updates the rotation angle based on the
// pointer's angle relative to the coordinate-system origin.
handleDisk.addInputListener( new DragListener( {
drag: ( event ) => {
const p = positionNode.globalToLocalPoint( event.pointer.point );
this.rotationAngleProperty.value = Math.atan2( p.y, p.x );
handleDisk.addInputListener( new RichDragListener( {
dragListenerOptions: {
drag: ( event ) => {
const p = positionNode.globalToLocalPoint( event.pointer.point );
this.rotationAngleProperty.value = Math.atan2( p.y, p.x );
},
},
keyboardDragListenerOptions: {
keyboardDragDirection: 'leftRight',
dragSpeed: 100,
shiftDragSpeed: 20,
drag: ( _event, listener ) => {
this.rotationAngleProperty.value += listener.modelDelta.x * ( Math.PI / 180 );
},
},
tandem: Tandem.OPT_OUT,
} ) );

// ── Visibility: only shown once a video with a finite duration is loaded
Expand Down
13 changes: 10 additions & 3 deletions src/screen-name/view/KeyboardShortcutsNode.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { Node } from "scenerystack/scenery";
import { BasicActionsKeyboardHelpSection } from "scenerystack/scenery-phet";
import { Node, VBox } from "scenerystack/scenery";
import { BasicActionsKeyboardHelpSection, MoveDraggableItemsKeyboardHelpSection } from "scenerystack/scenery-phet";

export class KeyboardShortcutsNode extends Node {
public constructor() {
super();

this.addChild( new BasicActionsKeyboardHelpSection() );
this.addChild( new VBox( {
children: [
new BasicActionsKeyboardHelpSection(),
new MoveDraggableItemsKeyboardHelpSection(),
],
spacing: 16,
align: 'left',
} ) );
}
}