I have started learning CANVAS. After i started drawing some basic shapes, i wanted to make some modifications to them. For example, I am confused of how to modify length and width of rectangle. Should i have to clear the canvas and redraw or can i capture the object of that rectangle like the objects in java script.
The canvas is a raster graphics surface. modifying length and width of a rectangle is a vector action. It is possible to scale a raster, but losses in quality can/will occur. You can use vector graphics in the form of SVG. But if it is only a rectangle, use a div with a border overlay-ed on your canvas.
Related
I am using fabric.js for html 5 interactive canvas app. If the object scales larger than the canvas, the controls go invisible outside canvas. How to make it visible outside the canvas or is there a way to style those controllers in css.
So, in fabricjs controls are rendered on the canvas, so having controls outside canvas it is not possible.
You can still obtain the effect in this way, this is just a trace.
Make canvas big as 100% of window, or anyway very bigger than drawing area.
Then you can clip the drawing canvas with a rectangle.
If you need borders to define the drawing area you can still put an overlay image as fabricjs allow you.
If you need to have controls near the drawing canvas you will have to position them OVER the non drawing part of the canvas.
This will give you some additional tasks:
When you create some object you have to be sure that they go in the drawing area. If you consider position of objects, you have to consider that a translation has to be applied, because you have absolute position while user will position the object watching a fake top left corner of a drawing area and not the top left corner of the canvas.
The best thing you can do is make a larger canvas, but limit the drawing area to a limited part, like a margin. Not easy because after that you always need to consider the margin when making other calculations, but it is possible.
From my very limited html5 canvas experience, it seems like the way to animate something is to clear the entire canvas, and draw everything from scratch.
This doesn't seem very performant. I'm wondering why this was the chosen approach?
Is there an alternative? For example, using an object-oriented approach, if you wanted to re-render a tree in the foreground, the system should cache the background, and only rerender that layer.
Your understanding is correct.
Typical canvas apps will completely erase the canvas and redraw objects.
This process works well because Html Canvas is designed with blazingly fast drawing speed.
Unlike object oriented design, the data that draws on the canvas has been completely "flattened".
There is a single data array containing the Red, Green, Blue & Alpha components of all pixels on the canvas.
[
pixel1Red, pixel1Green, pixel1Blue, pixel1Alpha,
pixel2Red, pixel2Green, pixel2Blue, pixel2Alpha,
pixel3Red, pixel3Green, pixel3Blue, pixel3Alpha,
...
]
This means that any color component of any pixel can be accessed with a single jump.
This flat structure also means that if an image needs to be drawn on the canvas, the browser only needs to copy sequential data from the source image directly into sequential data in the canvas pixel array.
In addition, Canvas is hardware accelerated when a GPU is available.
That's the basic technique, yes. You could also clear a specific area of the canvas instead, using clearRect():
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes
// Clear the specified rectangular area from x, y through width, height.
context.clearRect(x, y, width, height);
In your case of change foregrounds and backgrounds, however, consider modifying the globalCompositeOperation, which enables you to draw shapes under existing shapes:
// Draw new shapes behind the existing canvas content.
ctx.globalCompositeOperation = 'destination-over';
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Compositing
Another useful method is clip(), which allows you to draw shapes as masks:
// Create a circular clipping path.
ctx.beginPath();
ctx.arc(0, 0, 60, 0, Math.PI * 2, true);
ctx.clip();
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Compositing
I need to blur render but not whole, only fragments. Frozen "glass" shapes will flowed over (SVG animated transparent shapes over WebGl animation). The problem is local frozen effect. Whether is some effect composer or context.readPixels + FastBlur.js makes sense or maybe css + masks ? Thank you for help.
I did it:
WebGl shader blur (Three.js render passes) + mask texture (image = additional invisible canvas element where shapes are drawn). SVG is an independent element, but gives information about kind of shapes and positions for mask texture and displays shapes of course. A bit crazy but works and very fast.
WebGl doesn't support line thickness. So when I need to highlight some line, I just draw rectangle around it. But when I zoom scene it looks pretty scary.
There are two ways I see now:
1) Recalculate rectangle width according to canvas.width into model coordinates.
2) Place all zoom-invariant objects under separate matrix (I use scenejs) and recalculate their positions after each mousewheel
I don't like both of this solution. So I wonder: is there good workaround to make items zoom invariant?
Another way around that (not the most efficient one though) might be to use shaders. In our WebGL app, we render highlighted primitives into a texture and then blur it back on screen to add a "selection glow effect".
I need to limit the drawing of an object to a rectangle. I can't just change the viewport to match the rectangle becouse the ModelView matrix (that should change the rectangle, but not the content) may not be identity. A solution that would work is to draw to a FBO that match the rectangle, then draw the FBO to the screen, but it seems to slow. Is there any better option to do that?
If I understood you correctly, glScissor should be the function you are looking for. It crops the rendering to a selected sub-rectangle of the viewport. This does not modify the viewport. So the objects cover the same size on the screen, it just prevents you from drawing any pixels outside of the scissor region. If this is not what you want and you want the sub-rectangle to contain the whole scene and thus your objects to shrink, then changing the viewport is the solution of choice.
EDIT: If you want the rectangle to be transformable and especially rotatable (and therefore not a rectangle anymore on the screen), then rendering into an FBO and using this as texture on a quad is probably the best solution. Otherwise you could probably also just modify the vertex coordinates after projection, thus multiplying the transformation matrix of the target rectangle with the projection matrix and using this as new projection matrix, but I'm not completely sure about that (but at least something similar should do it.