Given an HTML canvas that has already been drawn to, what's the best way to shade the whole canvas except given circular regions? (in context: shadows except where are there light sources)
I was hoping it would be as simple as a rect() followed by subsequent arc()s, but AFAIK there's no way to "remove" those circular sections after the fact. I can get close ( http://jsfiddle.net/mW8D3/2/), but the overlapping regions of circles end up shaded (in XOR fashion, whereas I want OR). Using clip() has the same problem.
I've also tried using globalCompositeOperation but can't quite seem to achieve what I want.
Any ideas?
You could first create the shadow image on a second canvas and knock out holes from it with globalCompositeOperation 'copy' and a transparent fillStyle.
Like this: http://jsfiddle.net/mW8D3/4/
Related
I'm creating an interactive d3 application that has one part of an interface that is very similar to Bostock's focus/context brushing example:
http://bl.ocks.org/mbostock/1667367
Everything is working fine so far, but here's what I want to do. I want to take the context region (bottom chart) and gaussian blur the regions on the brush background (and the svg chart path and x axis behind it) that are not selected by the brush extent. Basically, I'm trying to produce an effect similar to this:
http://bl.ocks.org/mbostock/4349545
but since my chart is a path rather than a bunch of little circles, I can't simply change the path class for the region that is selected.
My solution was to draw a couple of rectangles to the left and right of the brush extent, and to style those rectangles with fill-opacity, etc, which creates a "de-emphasized" effect similar to that brush handles example.
However, for true gaussian blur, it seems trickier. I can do an SVG filter on the regions themselves, but that just blurs the edge of the rectangles (it doesn't apply a blur effect to everything that is visible through them). My next solution was to try and get the BackgroundImage from the canvas and blur that, something like what what you see here:
http://www.w3.org/TR/SVG/filters.html#AccessingBackgroundImage
But for the life of me, I can't make it work. Is BackgroundImage supported from the browser? Do I need to tell d3 to re-call some of my page elements to repaint the svg elements (since they are dynamically loaded) inside of my brush callback? Is there another way altogether to do this?
Background image is only supported in IE10 and Opera - so what you're doing will work in Windows 8! The obvious workaround is to pull in the original background objects to the filter via feImage. This works in IE10, Opera and Webkit, but IE10+Opera treats the x,y coordinates supplied to feImage for internal content references differently than Webkit.
The next level workaround is to do the entire overlayer in filter effects, and set the filter on the content group. That's perfectly possible (but it might be a bit complicated to make it work in d3)
For some inspiration: http://codepen.io/mullany/pen/mnBqK
I'm trying to check if two objects (e.g. a rectangle and a triangle) on a HTML5 canvas are overlapping each other.
Currently I can only check that by looking at the screen (having set globalCompositeOperation='lighter').
My first idea would have been to scan all over the canvas if the "lighter" (compare code snippet above) color exists in the canvas. But therefor I would have to look at every single pixel which was rather costly for what I need.
Is there a (better) alternative to automatically check if they are overlapping?
Best regards.
The site below explains how to use the Separating Axis Theorem to determine if two convex shapes overlap.
http://www.codezealot.org/archives/55
To use this you will need to know the coordinate data used in contstructing the shapes.
I'm new to html5. And I'm trying to create a basic painting tool.
What I want to do in this tool is to have one or more shapes(maybe overlapping) and to paint the shapes without getting the colors overlapped. If a circle is drawn inside a rectangle and if I start coloring the circle, the rectangle should not be painted even if the mouse is dragged over it unless the dragging starts inside it.
To achieve this should I use multiple canvases or shapes?
Thanks in advance.
Well, first you need to program in the idea of keeping track of separate shapes. If you haven't already done that see here for a tutorial.
I imagine your shapes will all be kept as images or in-memory canvases themselves. I'm not sure how else you can do it.
There are a million ways you could do this, here's one:
When you start your drawing operation you need to detect which shape you're on. Then you draw that shape to an in-memory canvas and switch that temporary canvas' globalcompositeoperation to source-atop. This will make sure the paint can only paint in the already opaque regions of that shape (if that's your intent here, which it seems to be).
All while you are painting you will want to update the temporary canvas and redraw the main canvas constantly. While you are redrawing the main canvas, instead of painting that shape's image file you'll want to paint the temporary canvas (if you use canvases to keep the shapes you can just update those in real time).
If you are not using temporary canvases for each shape, when you stop the drawing operation you are gonna have to update the image associated with the shape to complete the operation.
Using an in-memory canvas (not added to the DOM) for every shape (that is the size of the shape and no larger) will make coding things slightly easier and might not be that bad on performance. I'd give it a try with 100 and 1000 (or more) in-memory canvases on your targeted platforms to see though.
The alternative is to use one in-memory canvas and have an HTMLImageElement (png) that represents every shape, but using the canvas.toImageURL function can be a bit of a performance hit in itself. I'd try both methods to see which works best in your case. If the shape count is small enough, it probably doesn't matter which.
I have a large source image and I want to display a small section of it inside a circle, with leaving the part of the canvas outside of the circle transparent.
The Mozilla guide to Compositing with HTML5 covers two topics: globalCompositeOperation and clip. It looks like both of these will let me do what I want, so I'm wondering what the drawbacks are of each, and which I should use.
I could set globalCompositeOperation to source-atop (or source-in, but that seems buggy in WebKit). Then have the destination canvas be transparent with a black circle, and simply draw the source image over that. This will ensure that only the circle part will be filled in.
Or, I could draw a circular path and use clip to define a clipping region, then draw the source image over that, which should also ensure only the circle part will be filled in (in fact, Mozilla's page above even has an example of doing pretty much that with stars).
Will both of these techniques work as I say they will, or am I missing something?
If so, are there any major gotchas with either of these techniques which makes one clearly better than the other?
If not, which one has better performance in general?
I would (purely speculatively) imagine the globalCompositeOperation would have better performance, since it is applying the operation on a per-pixel level, whereas the clip operation needs to do polygon intersection. But that's just a hunch.
As of March, globalCompositeOperation did not work the same on all browsers.
Clip does... except the anti-aliasing, actually, which is sadly different per browser.
In my opinion the appropriate thing to do here is use clip. Using source-atop may work for your very specific situation, but it isn't very extensible as you described it. If you ever want to change any of it, like say have a background behind your circle, you'll run into trouble if you do it the globalComposite way.
And the tests are in: Clip is faster in every browser I tested, and massively faster in Firefox. See the results or try for yourself here
I have a small project I am working on HTML5 canvas and I wanted to get some ideas how to accomplish it. I have built an outline of a tree using all the canvas line functions. lineTo, bezierCurveTo, quadracticCurve, etc. I have attached a picture of the outline. Now, what I would like to do is have some code that fills a percent of this outline. Kind of like a progress bar starting from the bottom. Does anyone have ideas on how to accomplish this?
Thanks
Rather than thinking of the problem as having to fill a percentage of the inside of the tree, why not split the image into two layers, the tree and the "fill", and then draw one over the other. See my image below for a quick and dirty example.
Of course, you will need to obscure the rest of the "fill" layer, so you will need to fill the outside of the tree shape white, but this should be fairly easy as you already have the path worked out. In essence, your path would instead of being the outside edge of a a tree shape, become the inside edge of a tree shaped hole!