Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions modules/core/src/controllers/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,12 @@ export default abstract class Controller<ControllerState extends IViewState<Cont
isPanning: true
}
);

// When there's no transition (duration = 0), immediately reset interaction state
// since _onTransitionEnd callback won't fire
if (!smooth) {
this._setInteractionState({isZooming: false, isPanning: false});
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason not to reset all 5 states?

}
return true;
}

Expand Down
58 changes: 58 additions & 0 deletions test/modules/core/controllers/controllers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,64 @@ test('OrthographicController scroll zoom responds without transition lag', t =>
t.end();
});

test('OrthographicController scroll zoom resets isZooming state', t => {
const timeline = new Timeline();
const view = new OrthographicView({controller: true});
const baseProps = {
id: 'test-view',
x: 0,
y: 0,
width: 100,
height: 100,
target: [0, 0, 0],
zoom: 0,
scrollZoom: true
};
const controllerProps = {...view.controller, ...baseProps};
const ControllerClass = controllerProps.type;

let currentProps = {...controllerProps};
const interactionStates: any[] = [];

const controller = new ControllerClass({
timeline,
onViewStateChange: ({viewState}) => {
currentProps = {...currentProps, ...viewState};
controller.setProps(currentProps);
},
onStateChange: state => {
interactionStates.push({...state});
},
makeViewport: viewState =>
view.makeViewport({width: currentProps.width, height: currentProps.height, viewState})
});

controller.setProps(currentProps);

const wheelEvent = {
type: 'wheel',
offsetCenter: {x: 50, y: 50},
delta: -1,
srcEvent: {preventDefault() {}},
stopPropagation: () => {}
};

controller.handleEvent(wheelEvent as any);

// Verify we get exactly 2 state changes for non-smooth scroll zoom
t.is(interactionStates.length, 2, 'scroll zoom triggers exactly 2 state changes');

// Verify first state has isZooming: true
t.is(interactionStates[0].isZooming, true, 'isZooming is set to true at start');
t.is(interactionStates[0].isPanning, true, 'isPanning is set to true at start');

// Verify last state has isZooming: false
t.is(interactionStates[1].isZooming, false, 'isZooming is reset to false at end');
t.is(interactionStates[1].isPanning, false, 'isPanning is reset to false at end');

t.end();
});

test('FirstPersonController', async t => {
await testController(
t,
Expand Down
Loading