diff --git a/UItests/test.spec.ts b/UItests/test.spec.ts
index 97a16b3..a74f905 100644
--- a/UItests/test.spec.ts
+++ b/UItests/test.spec.ts
@@ -127,6 +127,72 @@ test("Create curved line", async ({ page }) => {
await checkNumberOfElementsInLocalStorage(page, 0)
})
+test("Zoom", async ({ page }) => {
+ await page.goto('http://localhost:5173/');
+ // zoom by clicking zoomBar
+ const zoomDownBtn = page.locator('[id=zoomdown]')
+ const zoomUpBtn = page.locator('[id=zoomup]')
+ const zoomReset = page.locator('[id=zoomreset]')
+ await zoomDownBtn.click()
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "width", value: 2112 }) //1920px+192px(10%)
+ await zoomUpBtn.click()
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "percentage", value: 100 })
+ await page.pause()
+ // zoom by keyPress ctrl/meta + "+"/"-"
+ await page.locator('#canvas').press('Control++')
+ await page.keyboard.up("+")
+ await page.keyboard.up("Control")
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "height", value: 972 }) //1080px - 108px(10%)
+ await page.locator('#canvas').press('Meta+-')
+ await page.keyboard.up("-")
+ await page.keyboard.up("Meta")
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "percentage", value: 100 })
+ // zoom by keyPress + wheel scroll
+ await page.mouse.move(700, 400);
+ await page.keyboard.down('Control')
+ await page.mouse.wheel(0, 500);
+ await page.keyboard.up("Control")
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "percentage", value: 90 })
+ // reset zoom (centered)
+ await zoomReset.click()
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "percentage", value: 100 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "width", value: 1920 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "height", value: 1080 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "x", value: 0 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "y", value: 0 })
+})
+
+test("Grab canvas", async ({ page }) => {
+ await page.goto('http://localhost:5173/');
+ const zoomReset = page.locator('[id=zoomreset]')
+ const toolbarGrab = page.locator('header > [id=canvasGrabBtn]')
+ await toolbarGrab.click()
+ // await page.locator('#canvas').click() // it's need if testing in --headed mode
+ await page.mouse.move(600, 600);
+ await page.mouse.down();
+ await page.mouse.move(700, 700);
+ await page.mouse.up();
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "x", value: -1 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "y", value: -1 })
+ // reset grab (centered)
+ await zoomReset.click()
+ // await page.locator('#canvas').click() // it's need if testing in --headed mode
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "percentage", value: 100 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "width", value: 1920 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "height", value: 1080 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "x", value: 0 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "y", value: 0 })
+ // grab by keyPress + mouse move
+ await page.mouse.move(600, 600);
+ await page.keyboard.down('Control')
+ await page.mouse.down();
+ await page.mouse.move(400, 400);
+ await page.mouse.up();
+ await page.keyboard.up("Control")
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "x", value: 1 })
+ await checkCanvasViewBoxParametersInLocalStorage(page, { key: "y", value: 1 })
+})
+
async function checkElementInLocalStorage(page: Page, elementType: string) {
return await page.waitForFunction(type => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -141,6 +207,22 @@ async function checkNumberOfElementsInLocalStorage(page: Page, expected: number)
}, expected);
}
+async function checkCanvasViewBoxParametersInLocalStorage(page: Page, param: { key: string; value: number }) {
+ return await page.waitForFunction(param => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if (param.key === "x" || param.key === "y") {
+ if (param.value <= 0) {
+ return JSON.parse(localStorage['canvasViewBox'])[param.key] <= param.value;
+ }
+ if (param.value >= 0) {
+ return JSON.parse(localStorage['canvasViewBox'])[param.key] >= param.value;
+ }
+ } else {
+ return JSON.parse(localStorage['canvasViewBox'])[param.key] === param.value;
+ }
+ }, param);
+}
+
// let context;
diff --git a/src/App.tsx b/src/App.tsx
index 77dc439..2ff218b 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,15 +1,35 @@
+import { useAtom } from 'jotai';
import Canvas from './components/Canvas';
import Inspector from './components/Inspector';
import Layers from './components/Layers';
import Toolbar from './components/Toolbar';
+import Zoom from './components/Zoom';
+import { onKeyPressAtom } from './store/store';
const App = () => {
+ const [, onKeyPress] = useAtom(onKeyPressAtom);
+
return (
-
+
{
+ if (e.key === '+' || e.key === '-') {
+ e.preventDefault();
+ }
+ onKeyPress({ ctrlKey: e.ctrlKey || e.metaKey, key: e.key });
+ }}
+ onKeyUp={(e) => {
+ if (e.key === '+' || e.key === '-') {
+ e.preventDefault();
+ }
+ onKeyPress({ ctrlKey: e.ctrlKey || e.metaKey, key: '' });
+ }}
+ >
+
);
};
diff --git a/src/components/Canvas.tsx b/src/components/Canvas.tsx
index 8cb33f9..67fda7c 100644
--- a/src/components/Canvas.tsx
+++ b/src/components/Canvas.tsx
@@ -1,4 +1,4 @@
-import { useRef } from 'react';
+import { useEffect, useRef } from 'react';
import { useAtom, useAtomValue } from 'jotai';
import SingleElement from './SingleElement';
import SelectingArea from './SelectingArea';
@@ -9,10 +9,14 @@ import {
onMouseMoveAtom,
isDraggingAtom,
isDrawingAtom,
- onKeyPressAtom,
- initialElementAtom,
+ keyPressedAtom,
+ canvasViewBoxAtom,
+ zoomCanvasAtom,
+ creationInitialElementAtom,
+ selectingAreaAtom,
+ grabCanvasAtom,
} from '../store/store';
-import { ElemenEvent } from '../types/CommonTypes';
+import { ElemenEvent, ZoomCanvasFn } from '../types/CommonTypes';
import { transformCoordinates } from '../assets/utilities';
const Canvas = () => {
@@ -22,8 +26,12 @@ const Canvas = () => {
const [, onMouseUp] = useAtom(onMouseUpAtom);
const [, onMouseDown] = useAtom(onMouseDownAtom);
const [, onMouseMove] = useAtom(onMouseMoveAtom);
- const [, onKeyPress] = useAtom(onKeyPressAtom);
- const initialElement = useAtomValue(initialElementAtom);
+ const keyPressed = useAtomValue(keyPressedAtom);
+ const canvasViewBox = useAtomValue(canvasViewBoxAtom);
+ const [, zoomCanvas] = useAtom(zoomCanvasAtom);
+ const [, grabCanvas] = useAtom(grabCanvasAtom);
+ const creationInitialElement = useAtomValue(creationInitialElementAtom);
+ const selectingArea = useAtomValue(selectingAreaAtom);
const svgContainerRef = useRef
(null);
@@ -51,16 +59,44 @@ const Canvas = () => {
});
};
+ // for prevent default browser zoom
+ useEffect(() => {
+ const handleOnWheel = (e: WheelEvent) => {
+ e.preventDefault();
+ if (keyPressed.ctrlKey && e.deltaY < 0) {
+ zoomCanvas(ZoomCanvasFn.ZOOMUP);
+ }
+ if (keyPressed.ctrlKey && e.deltaY > 0) {
+ zoomCanvas(ZoomCanvasFn.ZOOMDOWN);
+ }
+ if (!keyPressed.ctrlKey) {
+ grabCanvas({ x: 0, y: e.deltaY });
+ }
+ };
+
+ const containerElement = svgContainerRef.current;
+
+ if (containerElement) {
+ containerElement.addEventListener('wheel', handleOnWheel, {
+ passive: false,
+ });
+
+ return () => {
+ containerElement.removeEventListener('wheel', handleOnWheel);
+ };
+ }
+ }, [keyPressed.ctrlKey, zoomCanvas, grabCanvas]);
+
return (