Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eraser #6994

Merged
merged 142 commits into from
May 14, 2021
Merged

Eraser #6994

merged 142 commits into from
May 14, 2021

Conversation

ShaMan123
Copy link
Contributor

@ShaMan123 ShaMan123 commented Apr 7, 2021

This PR adds an ERASER brush.

You can test it in codesandbox.

UPDATE: The eraser has moved https://github.com/ShaMan123/erase2d

Inspiration

#1225 (comment)

Object Logic

  1. When path is created it is attached to all objects that intersect the eraser path
  2. Add the new path to existing object eraser paths
  3. use clipPath attr and EraserPath to achieve erasing effect

Brush Rendering Logic

EraserBrush extends PencilBrush.
Use top context to achieve an erasing effect while drawing - draw canvas on top context and leave only non erasable objects on main context. This way when the user erases the top context is drawn out and the main context with non erasables is revealed. 🚀💪👍👍

  1. Draw all non-erasable objects on bottom ctx with the exception of overlays renderBottomLayer
  2. Draw all objects and erasable drawables on top ctx renderTopLayer
  3. Draw eraser fabric.PencilBrush#_render at renderTopLayer
  4. Draw non-erasable overlay renderOverlay

The canvas is prepared for every step/layer according to appropriate logic, hiding unnecessary objects and restoring them after painting.

Layer 1 is drawn on main/bottom ctx, the rest on top ctx.
Layers 2, 3 are affected by the brush.

Usage

added erasable option to Object controlling whether it can be erased by the brush.
EraserBrush is the same as PencilBrush in terms of use.

Caveats

1. Currently using absolutePositioned for clipPath - this causes a problem when selecting and moving an erased object. The eraser paths don't move with the object. I'm pretty sure there's some kind of transform function available to render the clipPath relatively. Would be glad to know which. Fixed 6d9c7ff
2. onMouseMove is a challange - I have changed the drawing context (from canvas.contextTop to canvas.getContext()) so that the brush behaves as a clip path for the entire canvas. Not desirable though, in case of objects which are not erasable. I've seen that animated objects are drawn on a different canvas as well so that needs to be addressed. DONE 127de4b
3. I haven't addressed export/import of eraser data as part of the clip path Need to handle toSVG export to svg now supported 1257489 47e6873, REMAINING fromSVG
4. Using animation when erasing needs handling DONE

Performance

Superb!

Motivation is obvious

#1225 #5742 #6356 #6261 #5595 #5273 #5188 #6964

@ShaMan123
Copy link
Contributor Author

ShaMan123 commented Apr 7, 2021

Regarding 302a23b
I suggest renaming absolutePositioned: boolean to clipPathPosition: 'relative' | 'absolute' | 'fixed' so data export/import can be addressed properly
stale

ShaMan123 added 11 commits April 7, 2021 22:52
This reverts commit cce4ac1.
handle transform in dedicated clip path group instead of in canvas
Only erasable objects will be visibly affected by the eraser brush.
       * In order to support selective erasing all non erasable objects are rendered on the main ctx
       * while the entire canvas is rendered on the top ctx.
       * When erasing occurs, the path clips the top ctx and reveals the main ctx.
       * This achieves the desired effect of seeming to erase only erasable objects.
@ShaMan123
Copy link
Contributor Author

I see the tests fail because of erasable option that isn't in the test files...

@asturur
Copy link
Member

asturur commented May 14, 2021

Let me see if with build:fast fixed it pass.

@asturur
Copy link
Member

asturur commented May 14, 2021

Ok there are just some minor lint issues. can you run npm run lint locally and fix them?

@ShaMan123
Copy link
Contributor Author

lint passed 0f81013

@asturur asturur merged commit f79503b into fabricjs:master May 14, 2021
@asturur
Copy link
Member

asturur commented May 14, 2021

Would be cool if we can work on a demo for the main website

@johannbuscail
Copy link

Hi ! Do you know when this feature will be published to the NPM package ?

@asturur
Copy link
Member

asturur commented May 16, 2021

Next release is in automatically. Soon since we also merged RTL text

@ShaMan123
Copy link
Contributor Author

Would be cool if we can work on a demo for the main website

@asturur Could you point me to the exact place where I can add a demo in the website repo?
I don't understand what goes where

@asturur
Copy link
Member

asturur commented May 20, 2021

https://github.com/fabricjs/fabricjs.com/blob/gh-pages/posts/demos/_posts/2020-2-15-custom-control-render.md

This is an example of the demo.
You create a new file in the same folder, and start writing.

To load the website locally:
you clone the repo in the same parent folder of fabricJS, so that fabric.js and fabricjs.com are siblings.
Then in fabricjs.com folder you run jekyll serve.
If you are on windows, i have no idea how to exactly have it running. It works well on mac and linux.

@asturur asturur mentioned this pull request May 22, 2021
@goldingdamien
Copy link

Is there any user documentation for this?
I installed version 4.5.0 but there is no fabric.EraserBrush.
How do I reference this feature from the fabric npm package?

@ShaMan123
Copy link
Contributor Author

fabricjs/fabricjs.com#306

It is excluded from the default build so you need to create a custom build

@goldingdamien
Copy link

@ShaMan123

I would like to use this feature while using the npm module for simplicity.
Can you confirm, doing the following is correct.
Thank you.

Add and execute below:
https://github.com/ShaMan123/fabric.js/blob/6d9c7fffa4c5c6ece49a97380fa0965aeb7bb7e1/src/brushes/eraser_brush.class.js

// Enable EraserBrush:
canvas.freeDrawingBrush = new fabric.EraserBrush(canvas);
canvas.freeDrawingBrush.width = 10;
canvas.isDrawingMode = true;

// Optionally use "erasable" property to enable/disable ability for object to be erased:
const t = new fabric.Triangle({
  top: 300,
  left: 210,
  width: 100,
  height: 100,
  fill: "blue",
  erasable: false
});

@ShaMan123
Copy link
Contributor Author

@ShaMan123

I would like to use this feature while using the npm module for simplicity.

As would I.
Looks good.

@matsu-motsu
Copy link

@ShaMan123

fabricjs/fabricjs.com#306

Thank you!
However, It seems to be incompatible with the SprayBrush.
After spraying, I used an eraser and my computer's memory boiled.
https://codepen.io/matsu-motsu/pen/xxqWjdZ

@ShaMan123
Copy link
Contributor Author

@ShaMan123

fabricjs/fabricjs.com#306

Thank you!
However, It seems to be incompatible with the SprayBrush.
After spraying, I used an eraser and my computer's memory boiled.
https://codepen.io/matsu-motsu/pen/xxqWjdZ

@matsu-motsu Great, look at the fix #7100

@asturur
Copy link
Member

asturur commented Jun 6, 2021

You can use it from the npm module anyway, you can add a post-install script in your installation that will rebuild fabric adding the module.

@goldingdamien
Copy link

Thanks latest fix got rid of erased area returning after mouseup issue.

@goldingdamien
Copy link

@ShaMan123 There is an issue in my environment where I am using IText and when using this eraser function, the last IText object disappears while mouse is down but returns on mouseup.

@ShaMan123
Copy link
Contributor Author

@goldingdamien
Copy link

@ShaMan123 Ok, thanks for checking, if I can replicate the problem in the sandbox I'll let you know.

@tanzyy96
Copy link

I'm currently using this feature and it seems great! One issue though is that even after completely deleting all a drawing, the drawing remains selectable as an invisible group. Is there any way to clear the "erased" drawings? I need to export the JSON and I'm worried it becomes infinitely large.

@ShaMan123
Copy link
Contributor Author

@tanzyy96 #6994 (comment)_

@brunobrante
Copy link

How can I remove erased objects in canvas, only when I have fully erased the object?

@ShaMan123
Copy link
Contributor Author

#8586

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants