Merge branch 'master' into editor-agent-more-tools
This commit is contained in:
@@ -2320,15 +2320,24 @@ describe('ImageCanvasEditorView', () => {
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('uses normal wheel for vertical canvas scroll and ctrl wheel for zoom', () => {
|
||||
it('uses normal wheel for two-axis canvas pan and ctrl wheel for zoom', () => {
|
||||
render(<ImageCanvasEditorView />);
|
||||
|
||||
const viewport = screen.getByLabelText('画布工作区');
|
||||
const world = screen.getByTestId('image-canvas-world') as HTMLElement;
|
||||
expect(
|
||||
screen.getByRole('button', { name: '当前缩放比例 100%' }),
|
||||
).toBeTruthy();
|
||||
|
||||
fireEvent.wheel(viewport, { deltaY: 120, clientX: 400, clientY: 280 });
|
||||
fireEvent.wheel(viewport, {
|
||||
deltaX: 80,
|
||||
deltaY: 120,
|
||||
clientX: 400,
|
||||
clientY: 280,
|
||||
});
|
||||
expect(world.style.transform).toBe(
|
||||
'translate(-80px, -120px) scale(0.5)',
|
||||
);
|
||||
expect(
|
||||
screen.getByRole('button', { name: '当前缩放比例 100%' }),
|
||||
).toBeTruthy();
|
||||
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
moveViewportFromMinimapDrag,
|
||||
moveViewportFromMinimapPointer,
|
||||
moveViewportFromPan,
|
||||
panViewportFromWheel,
|
||||
scaleViewportFromScreenPoint,
|
||||
scrollViewportVertically,
|
||||
selectCanvasObjectsInsideMarquee,
|
||||
selectLayersInsideMarquee,
|
||||
zoomViewportFromWheel,
|
||||
@@ -133,11 +133,13 @@ describe('ImageCanvasInteractionModel', () => {
|
||||
).toEqual({ x: 100, y: 60 });
|
||||
});
|
||||
|
||||
it('scrolls vertically and zooms around a screen point', () => {
|
||||
it('pans from two-axis wheel input and zooms around a screen point', () => {
|
||||
const viewport = { x: 10, y: 20, scale: 1 };
|
||||
|
||||
expect(scrollViewportVertically(viewport, 120)).toEqual({
|
||||
x: 10,
|
||||
expect(
|
||||
panViewportFromWheel({ viewport, deltaX: 40, deltaY: 120 }),
|
||||
).toEqual({
|
||||
x: -30,
|
||||
y: -100,
|
||||
scale: 1,
|
||||
});
|
||||
|
||||
@@ -212,12 +212,18 @@ export function scaleViewportFromScreenPoint({
|
||||
};
|
||||
}
|
||||
|
||||
export function scrollViewportVertically(
|
||||
viewport: CanvasViewport,
|
||||
deltaY: number,
|
||||
) {
|
||||
export function panViewportFromWheel({
|
||||
viewport,
|
||||
deltaX,
|
||||
deltaY,
|
||||
}: {
|
||||
viewport: CanvasViewport;
|
||||
deltaX: number;
|
||||
deltaY: number;
|
||||
}) {
|
||||
return {
|
||||
...viewport,
|
||||
x: viewport.x - deltaX,
|
||||
y: viewport.y - deltaY,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ export const IMAGE_CANVAS_SHORTCUT_SECTIONS: ImageCanvasShortcutSection[] = [
|
||||
{
|
||||
title: '视图',
|
||||
items: [
|
||||
{ action: '纵向滚动画布', keys: ['鼠标滚轮'], status: 'ready' },
|
||||
{ action: '平移画布', keys: ['鼠标滚轮 / 触控板'], status: 'ready' },
|
||||
{ action: '横向平移画布', keys: ['Shift', '鼠标滚轮'], status: 'ready' },
|
||||
{ action: '以鼠标位置缩放', keys: ['Ctrl', '鼠标滚轮'], status: 'ready' },
|
||||
{ action: '显示全部元素', keys: ['Ctrl', '0'], status: 'new' },
|
||||
{ action: '缩放至 100%', keys: ['Ctrl', '1'], status: 'new' },
|
||||
|
||||
@@ -1083,6 +1083,22 @@ describe('useImageCanvasStageInteractions', () => {
|
||||
});
|
||||
expect(screen.getByTestId('panning').textContent).toBe('true');
|
||||
|
||||
act(() => {
|
||||
fireEvent(
|
||||
viewport,
|
||||
new MouseEvent('pointermove', {
|
||||
bubbles: true,
|
||||
clientX: 140,
|
||||
clientY: 70,
|
||||
button: 1,
|
||||
buttons: 4,
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(screen.getByTestId('viewport-state').textContent).toBe(
|
||||
'40.0,-30.0,1',
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fireEvent(
|
||||
viewport,
|
||||
|
||||
@@ -158,19 +158,12 @@ describe('useImageCanvasViewportControls', () => {
|
||||
expect(captureCanvasHistory).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('handles vertical wheel scroll, ctrl wheel zoom and minimap movement', () => {
|
||||
const rafCallbacks: FrameRequestCallback[] = [];
|
||||
vi.spyOn(window, 'requestAnimationFrame').mockImplementation(
|
||||
(callback: FrameRequestCallback) => {
|
||||
rafCallbacks.push(callback);
|
||||
return rafCallbacks.length;
|
||||
},
|
||||
);
|
||||
vi.spyOn(window, 'cancelAnimationFrame').mockImplementation(() => {});
|
||||
it('keeps ordinary mouse wheel vertical and maps Shift wheel to horizontal', () => {
|
||||
const { result, viewportElement } = renderViewportControls();
|
||||
|
||||
act(() => {
|
||||
fireEvent.wheel(viewportElement, {
|
||||
deltaX: 0,
|
||||
deltaY: 120,
|
||||
clientX: 260,
|
||||
clientY: 190,
|
||||
@@ -182,6 +175,47 @@ describe('useImageCanvasViewportControls', () => {
|
||||
scale: 0.5,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.wheel(viewportElement, {
|
||||
shiftKey: true,
|
||||
deltaX: 0,
|
||||
deltaY: 80,
|
||||
clientX: 260,
|
||||
clientY: 190,
|
||||
});
|
||||
});
|
||||
expectViewport(result.current.viewport, {
|
||||
x: -340,
|
||||
y: -50,
|
||||
scale: 0.5,
|
||||
});
|
||||
});
|
||||
|
||||
it('handles native two-axis wheel pan, ctrl wheel zoom and minimap movement', () => {
|
||||
const rafCallbacks: FrameRequestCallback[] = [];
|
||||
vi.spyOn(window, 'requestAnimationFrame').mockImplementation(
|
||||
(callback: FrameRequestCallback) => {
|
||||
rafCallbacks.push(callback);
|
||||
return rafCallbacks.length;
|
||||
},
|
||||
);
|
||||
vi.spyOn(window, 'cancelAnimationFrame').mockImplementation(() => {});
|
||||
const { result, viewportElement } = renderViewportControls();
|
||||
|
||||
act(() => {
|
||||
fireEvent.wheel(viewportElement, {
|
||||
deltaX: 40,
|
||||
deltaY: 120,
|
||||
clientX: 260,
|
||||
clientY: 190,
|
||||
});
|
||||
});
|
||||
expectViewport(result.current.viewport, {
|
||||
x: -300,
|
||||
y: -50,
|
||||
scale: 0.5,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.wheel(viewportElement, {
|
||||
ctrlKey: true,
|
||||
@@ -191,7 +225,7 @@ describe('useImageCanvasViewportControls', () => {
|
||||
});
|
||||
});
|
||||
expectViewport(result.current.viewport, {
|
||||
x: -312,
|
||||
x: -356,
|
||||
y: -74,
|
||||
scale: 0.55,
|
||||
});
|
||||
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
getWorldPointFromClient,
|
||||
moveViewportFromMinimapDrag as resolveViewportFromMinimapDrag,
|
||||
moveViewportFromMinimapPointer as resolveViewportFromMinimapPointer,
|
||||
panViewportFromWheel,
|
||||
scaleViewportFromScreenPoint,
|
||||
scrollViewportVertically,
|
||||
zoomViewportFromWheel,
|
||||
} from './ImageCanvasInteractionModel';
|
||||
|
||||
@@ -260,8 +260,16 @@ export function useImageCanvasViewportControls({
|
||||
}
|
||||
|
||||
if (!event.ctrlKey && !event.metaKey) {
|
||||
const useShiftWheelHorizontalFallback =
|
||||
event.shiftKey && event.deltaX === 0;
|
||||
setViewport((currentViewport) =>
|
||||
scrollViewportVertically(currentViewport, event.deltaY),
|
||||
panViewportFromWheel({
|
||||
viewport: currentViewport,
|
||||
deltaX: useShiftWheelHorizontalFallback
|
||||
? event.deltaY
|
||||
: event.deltaX,
|
||||
deltaY: useShiftWheelHorizontalFallback ? 0 : event.deltaY,
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user