A diagram drawing application which is demonstrating how we can utilize React.js and HTML <canvas/> to create an interactive drawing.
https://draw.crispyscript.com (works best in desktop)
Demo.mp4
- Line drawing tool
- Rectangle drawing tool
- Pencil drawing tool(free-hand)
- Selection tool for moving and resizing a single element
- Undo/Redo/Clear
- Text tool
- Support deleting a selected element
- Arrow drawing tool
- Pan
- Zoom
- CSS & Styling
- Mobile & Resizing friendly
- Multi-select elements
- Support uploading an image
- Duplicate elements
- Send to back/front
- Save the result to file / local storage (need to serialize the image)
- Limit max history stack to ~50 items
- Export canvas to png/jpeg
- Rotate
- Keyboard shortcut
- Setting stroke color
- Setting stroke width
- Filled rectangle
- Copy & Paste elements (upgrade "Duplicate" feature)
- Run
yarnto install all dependencies - Run
yarn startto start the app locally
- Run
yarn visual:testto do regression test - If there is any failed test, investigate it one-by-one by going to
./cypress/snapshots/diffdirectory. - After a specific test file is fixed. To override all base screenshots of that file, run the following command.
# We want to override ALL screenshots for test-file.cy.js file yarn cypress run --env type=base --config screenshotsFolder=cypress/snapshots/base,trashAssetsBeforeRuns=false --spec "cypress/e2e/test-file.cy.js"
- Repeat step 2-3 until
yarn visual:testresults all passed. - Only after all tests are passed, clean up all existing screenshots and re-create them from scratch by running
yarn visual:dangerously-override-all-base. Note that, this command is dangerous since you will lose all existing screenshots.
Note: Tests may fail due to OS difference. All base screenshots are created on Macbook Pro 13".
More info: cypress-visual-regression Doc
The following functions are temporary. Mostly use for debugging. In the future, we will implement a proper export/import feature.
exportSnapshot()to export the diagram (must not have any image element)importSnapshot(value)to import,valueis the result of callingexportSnapshot()(must not have any image element)
- Most of x, y value are in
scenecoordinate (i.e. canvas coord, not viewport coord). They are inconsistency in naming. For example,// All of these variable names are in `scene` coord let sceneX, x1, x2, pointerX
- However, the
viewportcoordinate is more consistency in naming.// There always be `viewport` keyword in `viewport` coord let viewportX