feat: Implement support for gesture-based PTZ control (#2378)

- Closes: #1839
This commit is contained in:
Dermot Duffy
2026-02-28 20:36:53 -08:00
committed by GitHub
parent 40ad3b4460
commit ea86ad0016
32 changed files with 1714 additions and 126 deletions
@@ -142,6 +142,34 @@ describe('PTZController', () => {
});
});
describe('hasPhysicalPTZ', () => {
it('should return false without camera', () => {
const controller = new PTZController(document.createElement('div'));
expect(controller.hasPhysicalPTZ()).toBeFalsy();
});
it('should return false without PTZ capability', () => {
const controller = new PTZController(document.createElement('div'));
controller.setCamera(createCameraManager(), 'camera.office');
expect(controller.hasPhysicalPTZ()).toBeFalsy();
});
it('should return true with PTZ capability', () => {
const cameraManager = createCameraManager();
vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue(
createCapabilities({
ptz: {
left: [PTZMovementType.Relative],
},
}),
);
const controller = new PTZController(document.createElement('div'));
controller.setCamera(cameraManager, 'camera.office');
expect(controller.hasPhysicalPTZ()).toBeTruthy();
});
});
describe('should get PTZ actions', () => {
it.each([
['left' as const],
@@ -364,6 +392,79 @@ describe('PTZController', () => {
});
});
describe('should toggle type', () => {
it('from gestures to buttons', () => {
const element = document.createElement('div');
const handler = vi.fn();
element.addEventListener('advanced-camera-card:action:execution-request', handler);
const controller = new PTZController(element);
const ev = new Event('click');
vi.spyOn(ev, 'stopPropagation');
controller.toggleTypeHandler(ev, 'gestures');
expect(ev.stopPropagation).toBeCalled();
expect(handler).toBeCalledWith(
expect.objectContaining({
detail: {
actions: {
action: 'fire-dom-event',
advanced_camera_card_action: 'ptz_controls',
type: 'buttons',
},
},
}),
);
});
it('from buttons to gestures', () => {
const element = document.createElement('div');
const handler = vi.fn();
element.addEventListener('advanced-camera-card:action:execution-request', handler);
const controller = new PTZController(element);
const ev = new Event('click');
controller.toggleTypeHandler(ev, 'buttons');
expect(handler).toBeCalledWith(
expect.objectContaining({
detail: {
actions: {
action: 'fire-dom-event',
advanced_camera_card_action: 'ptz_controls',
type: 'gestures',
},
},
}),
);
});
it('from undefined to gestures', () => {
const element = document.createElement('div');
const handler = vi.fn();
element.addEventListener('advanced-camera-card:action:execution-request', handler);
const controller = new PTZController(element);
const ev = new Event('click');
controller.toggleTypeHandler(ev);
expect(handler).toBeCalledWith(
expect.objectContaining({
detail: {
actions: {
action: 'fire-dom-event',
advanced_camera_card_action: 'ptz_controls',
type: 'gestures',
},
},
}),
);
});
});
describe('should handle action', () => {
it('successfully', () => {
const action = {