diff --git a/client/src/components/layerManager/useLayerManagerAlignedView.spec.ts b/client/src/components/layerManager/useLayerManagerAlignedView.spec.ts index c3b6e1081..b3129596d 100644 --- a/client/src/components/layerManager/useLayerManagerAlignedView.spec.ts +++ b/client/src/components/layerManager/useLayerManagerAlignedView.spec.ts @@ -1,7 +1,9 @@ // @vitest-environment jsdom +/* eslint-disable vue/one-component-per-file -- harness Host components for mount() */ import { defineComponent, ref, nextTick } from 'vue'; // eslint-disable-next-line import/no-extraneous-dependencies -- @vue/test-utils is only used in tests import { mount } from '@vue/test-utils'; +import { clientSettings } from 'dive-common/store/settings'; import type { MediaController, AggregateMediaController } from '../annotators/mediaControllerType'; import AlignedViewStore from '../../alignedView/AlignedViewStore'; import useLayerManagerAlignedView from './useLayerManagerAlignedView'; @@ -55,6 +57,7 @@ function makeHarness() { const viewer = { createLayer: vi.fn(() => warpLayer), geoOn: vi.fn(), + center: vi.fn(), layers: () => [nativeLayer, warpLayer], }; @@ -92,7 +95,7 @@ function makeHarness() { }); const wrapper = mount(Host); return { - wrapper, annotator, nativeFeature, warpFeature, imgA, + wrapper, annotator, nativeFeature, warpFeature, imgA, viewer, }; } @@ -225,3 +228,40 @@ describe('useLayerManagerAlignedView large-image native hide', () => { expect(nextOsm.visible).toHaveBeenCalledWith(false); }); }); + +describe('right-click recenter', () => { + /** The mouseclick handler AlignedImageLayer registered on the viewer. */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + function clickHandler(viewer: any) { + const call = viewer.geoOn.mock.calls.find((c: unknown[]) => c[0] === 'geo_mouseclick'); + return call[1] as (e: unknown) => void; + } + const rightClick = { geo: { x: 12, y: 34 }, buttonsDown: { right: true } }; + + afterEach(() => { + clientSettings.annotatorPreferences.lockedCamera.enabled = false; + }); + + it('does not recenter while the camera lock is off', async () => { + const { viewer } = makeHarness(); + await nextTick(); + clickHandler(viewer)(rightClick); + expect(viewer.center).not.toHaveBeenCalled(); + }); + + it('recenters on right-click once the camera lock is on', async () => { + clientSettings.annotatorPreferences.lockedCamera.enabled = true; + const { viewer } = makeHarness(); + await nextTick(); + clickHandler(viewer)(rightClick); + expect(viewer.center).toHaveBeenCalledWith({ x: 12, y: 34 }); + }); + + it('ignores a left-click even when the lock is on', async () => { + clientSettings.annotatorPreferences.lockedCamera.enabled = true; + const { viewer } = makeHarness(); + await nextTick(); + clickHandler(viewer)({ geo: { x: 1, y: 2 }, buttonsDown: { left: true } }); + expect(viewer.center).not.toHaveBeenCalled(); + }); +}); diff --git a/client/src/components/layerManager/useLayerManagerAlignedView.ts b/client/src/components/layerManager/useLayerManagerAlignedView.ts index 0ae34aa1c..237dff206 100644 --- a/client/src/components/layerManager/useLayerManagerAlignedView.ts +++ b/client/src/components/layerManager/useLayerManagerAlignedView.ts @@ -1,6 +1,7 @@ import { computed, watch, ComputedRef, Ref, } from 'vue'; +import { clientSettings } from 'dive-common/store/settings'; import type { AggregateMediaController, MediaController } from '../annotators/mediaControllerType'; import type AlignedViewStore from '../../alignedView/AlignedViewStore'; import AlignedImageLayer from '../../layers/AlignedImageLayer'; @@ -123,9 +124,11 @@ export default function useLayerManagerAlignedView(options: { } }, getTransform: () => alignedDisplayTransform.value, - // Right-click means "remove last point" while creating/editing - // geometry; recenter everywhere else. - getRecenterEnabled: () => !editingModeRef.value, + // Follows the camera-lock toggle, the existing control for "the camera may + // recenter itself". Never while creating/editing geometry, where + // right-click already means "remove last point". + getRecenterEnabled: () => !!clientSettings.annotatorPreferences.lockedCamera.enabled + && !editingModeRef.value, }); /**