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

Added clipping feature #114

Closed
wants to merge 0 commits into from
Closed

Added clipping feature #114

wants to merge 0 commits into from

Conversation

nestorrente
Copy link
Contributor

Now an object can "clip" its childs into its shape.

Before this change, the drawObject function restored the canvas before draw object's children. In that way, clipping feature was not possible.

Instead of restoring canvas and making again all parent's transformations, now the canvas is restored after children were drawn. This allows us to use the clip() function before draw the object's children.

I realized that the fillRect() function doesn't work fine with clip() -it paints the object above its children. That's the reason why I wrote the function fillRectClipping. This function executes a rect() then a fill() instead of a fillRect(). Using rect()+fill(), the object is painted below its children as expected.

Now the trick begins: when an object has a "clipChildren" property with a truthly value, the following happens:

  1. canvas.fillRect() function is replaced by fillRectClipping function (line 159).
  2. object's draw() function is invoked (line 160).
  3. canvas.fillRect() function is restored (line 161).
  4. canvas.clip() function is invoked (line 162).

When "clipChildren" property is not defined or it has a falsy value, only "obj.draw()" is invoked.

Here its an example of this clipping feature:

clipping_example

@koggdal
Copy link
Owner

koggdal commented Aug 19, 2015

This is really cool! 😃

The only suggestion I have is to not patch the fillRect method, but instead change the uses of fillRect and replace them with .rect() and .fill() (in the display objects that use it). And also do the same for strokeRect.

Great work, thanks!

@nestorrente
Copy link
Contributor Author

Well, I realized that canvas.clip() function only uses the last drawn path. In other words, it will not work with Display Objects with more than one path.

We cannot guarantee that "clipChildren" property will work on all Display Objects, because any programmer can create his own display object. With this in mind, I think that the best solution is setting "clipChildren" property as a custom property of some display objects (actually all except Line and Text).

When another programmer wants to create a new display object including the "clipChildren" property, he will have the resposibility of using "rect", "fill" and "stroke" (instead of "fillRect" and "strokeRect") and call canvas.clip() when "clipChildren" is true.

If you agree with this, I will adapt all the current display objects and push a new commit.

@koggdal
Copy link
Owner

koggdal commented Aug 20, 2015

Oh you're right. It is possible to clip off things by drawing to a secondary canvas with globalCompositeOperation set to either 'destination-in' or 'destination-out'. That way you'd also get better anti-aliasing on the edges. But, it's probably a lot more work to get that working properly, so I'm on board with your idea of adding clipChildren for the display objects that can support it.

@nestorrente
Copy link
Contributor Author

I have adapted the following Display Objects:

✔ Arc
✔ Ellipse
✔ Image (square containing the image area)
✘ Line (it has no area)
✔ Polygon
✔ Rectangle
✔ Sprite (square containing the current frame area)
✘ Text (clip doesn't work with fillText/strokeText)

I was just thinking about using globalCompositeOperation with a secondary canvas as you comment. That solution will work even with texts. But yes, is much more work and I don't know how much it costs in terms of performance.

For now we can use clip(), and improve it in the future. I will make a new commit in brief.

It is a pleasure to help the development of this library! 😀

@nestorrente
Copy link
Contributor Author

The new commit (cbbb645) includes the changes.

I am new using git, maybe its better for you copying the changed files instead of doing a merge:

src/draw.js
src/displayobjects/arc.js
src/displayobjects/ellipse.js
src/displayobjects/image.js
src/displayobjects/polygon.js
src/displayobjects/rectangle.js
src/displayobjects/sprite.js

@koggdal
Copy link
Owner

koggdal commented Aug 21, 2015

Great! 😃

Well it's a great chance to learn git a bit more then! You seem to have gotten my latest commits bundled into your second commit here. The workflow that I try to follow is basically this:

Add this official repo as a remote:

git remote add upstream https://github.com/koggdal/ocanvas.git

Start from the main development branch and pull in any changes from upstream:

git checkout develop
git pull upstream develop

Check out a new branch based on the current branch:

git checkout -b develop-patch-clipping

Make changes. Then stuff might have happened on upstream, so might want to pull these changes in, but as your commits are not merged to the main repo yet, you want your commits on top. You use rebase for this. First you need to sync the develop branch:

git checkout develop
git pull upstream develop

Then you need to make your branch be based on develop and put your commits on top:

git checkout develop-patch-clipping
git rebase develop

Most often this will go just fine. If code changed in upstream in the same place as your change, there might be a conflict that you'll need to resolve. There's lots of good docs online about that.

Right now you're in a bad state where your last commit contains stuff I changed on develop before. I think that git might be able to resolve that in a good way if you just sync the develop branch with upstream and then rebase develop-patch-clipping on top of develop. If not, fix the conflicts. If too difficult, remove the last commit (git reset --hard HEAD~1) and redo your changes. I can of course pick the changes manually if you'd rather prefer that, but learning is good :)

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.

None yet

2 participants