How does context.drawImage work - javascript

In HTML5, using the canvas object you can draw an image.
context.drawImage(imageObj, x, y);
How does this work under the hood? Is the browser drawing pixels or using svg? I do not see any svg elements being added to the dom, so I am assuming the browser is drawing pixels, but how does it accomplish this all? Is there a library that the browser is using?
For the sake of discussion I guess we could just consider Webkit, but I would also be interested in what other browsers (IE) do.

Canvas is a pixel-based interface, SVG is a markup-language for vector graphics, they are two very separate things.
If you add an image to canvas it loads it first into the dom and then renders it to the canvas.
You can use SVG in conjunction with Canvas though. Say you wanted your canvas app to scale, you could simply rerender your svg files in different sizes to the canvas like described here
Because SVG-graphics can be used like images, they can just be rendered onto canvas like images.
If you want to have more in depth knowledge about canvas just read the spec

Well...you asked!
Think of canvas as a big, living bitmap...and here are the details:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html

Related

Is there a way to use Fabric.js and p5.js on the same canvas

I'm working on a project and would like to use both p5.js and fabric.js on the same canvas. I need the functionality of fabric.js to drag around pictures on the canvas and p5.js to dynamically draw lines between the pictures as they're being dragged. I'm not sure if this is possible because it seems like both have their own separate canvas creation functions
p5.js
createCanvas(100, 50);
fabric.js
canvas = new fabric.Canvas('c');
The fabric line class seems a little too rigid to accomplish the effect I'm after, so I'm looking for either an idea for a workaround or a different library that would be better for drawing dynamic lines on a fabric canvas.
It is not possible to combine both of them with one canvas element. These libraries take full control of the canvas of reference. Even if you were able to initialise both libraries on the same canvas element you will loose whatever was displayed by p5.js on the first FarbicJS canvas.renderAll() function call.
I don't know what exactly is your problem, but as an alternative I think you could try to have two canvases on top of each other (since the canvas element is invisible by default). One running on FabricJS and one on p5.js and somehow interact with each other. But, that will add some additional complexity.

draw SVG image into CanvasRenderingContext2D

Is it possible to do something like this
var image = new Image();
image.src = 'img.svg';
context.drawImage(image, x, y); // context is an instance of CanvasRenderingContext2D
with a SVG image? Actually this code works, but I think the image is converted to .jpg or similar, because if I try to zoom the browser page the image becomes coarse.
Clarification : The image should be re-drawn many times in the canvas context (i.e. for movements), so suggestions like "use this library" should consider this fact.
EDIT
From previous discussions, the issue seems to be due to canvas properties (canvas is not browser-zoomable) and not due to incorrect loading. Can I get and modify (eventually) this property of canvas to realize my purpose? I have to draw necessarily on canvas, no other options unfortunately.
Translate rendered svg according to the wanted zoom level.
How to detect page zoom level in all modern browsers?
explains browser-zoom level detection. And you can use fabricjs for canvas manipulation (http://fabricjs.com/).

HTML5 SVG vs Canvas for big number of lines?

Question:
Is canvas more suitable than svg in the following case?
Case:
I'm drawing a chart (using d3js library) similar to this one (but with much more data):
http://mbostock.github.com/d3/talk/20111116/iris-parallel.html
It's based on an svg and it works fine for several thousands of lines (up to 5000), adding more lines (svg path) decreases the performance dramatically (scrolling in the page becomes slow)
Keep in mind: That I need to add mouse events (which is handy in svg)
Generally svg is better suited for vector images, like in your example. However canvas has a lot of benefits in modern browsers such as hardware acceleration, so for drawing the lines, as long as zooming, panning ect. isn't required performance will be using canvas.
Mouse events can be a pain using canvas, since you have to manually keep track of everything, so with 5000+ points using canvas it wont be fun. The trade off however will be once the points are drawn, assuming you only draw them once the page will behave fine regardless of the number of lines, since they are all drawn to a raster image and aren't part of the DOM.
Honestly though the best way to find it is to test what you currently have using canvas.
When performance becomes a problem, switching to canvas might be an option. In this case you can draw the canvas once. Afterwards it's pretty much treated like an image. Drawing might take some time, but afterwards it can be scaled pretty quickly. Note that it is possible to draw a rendered SVG to a canvas using the context.drawImage method (example). So you could keep your SVG generation code to create an SVG in the background, and then draw it to the canvas.
But keep in mind that it won't scale as beautiful as an SVG as soon as it is on the canvas. When the user zooms in, it will get blurry or pixely, depending on how the browser scales graphics.
Click events on canvas can be handled in two ways. Either keep an array of click targets, and add an onclick event handler to the canvas. When a click occurs, iterate the array and check which one is closest to the click coordinates.
The other option is to use hit regions. These have to be defined as polygonal paths.
+1 to everything said above. I've seen some amazing performance increases when using canvas over SVG and over compositing images using the DOM.
About manipulating the canvas image with mouse events, I imagine the best approach for an image such as you are describing is to abstract it away using a library like the following:
http://paperjs.org
http://kineticjs.com
http://www.createjs.com/#!/EaselJS
Keep your code away from the canvas itself and let a library do the thinking for you.

Pixel level access with Pixastic and RaphaelJS

I'm working on an image editor and I have to create some pixel manipulation methods applied on RaphaelJS images. I am considering using Pixastic library for pixel manipulation.
The problem is the I cannot link RaphaelJS image to Pixastic since RaphaelJS creates a SVG element and Pixastic requires an 'img' tag.
I have tried something like this but with no success
img = r.image("Assets/test.jpg", 40, 40, 260, 150);
img.node=Pixastic.process(img.node, "desaturate");
There's not really currently an easy way to do this. As mentioned already, in many browsers you can output to Canvas and then perform pixel-level transformations, but this transition from SVG to Canvas is destructive, as you have gone from a retained-mode context to an immediate-mode context, and you therefore lose all the niceties of the retained mode API, such as being able to register event listeners on individual shapes, or have a high-level API for transforming individual shapes (or groups of shapes).
However, if you don't need the element-level event handling, you might look into the dojox.gfx library, which provides a high-level, retained-mode, SVG-inspired API for drawing shapes, but also has a Canvas backend (VML and Silverlight too). I believe it is not possible to register event listeners on individual shapes when using the Canvas output, but you would be able to register an event handler on the root canvas element. It might be possible to then apply transformations with Pixtastic, but you might need to hack into the dojox.gfx Canvas render code a bit.
You might also look into SVG filters, which is as close to native support for pixel-level, raster graphics-style manipulation as it gets with SVG.
I also believe they're currently trying to combine the two specifications somewhat to make such work possible: http://lists.w3.org/Archives/Public/public-canvas-api/2011AprJun/0117.html
You could try drawing the svg to a canvas element check near the end of this article https://developer.mozilla.org/en/drawing_graphics_with_canvas. Then outputting the canvas to a base 64 encoded image. Not having worked with either RaphaelJS or pixastic I am not sure how well this would work.

HTML5 <canvas>: Performance implications of drawImage()

I was wondering if there were any performance differences in using drawImage() on a dynamically created canvas (i.e. document.createElement("canvas")) versus a canvas already created in the DOM (i.e. tags on a HTML page).
My thinking is that the "slow" part of drawImage() occurs when it actually has to display visuals to the user, though I could be wrong (can't find too much information on this).
Would it be substantially more expensive to draw a group of objects to a canvas in memory followed by a final draw to the "main" canvas than just drawing straight to the latter? I feel like it'd be better to have multiple canvases, at least for organizational purposes.
Related: Does the size of the canvas impact performance if you're only drawing to a subsection of it?
Talking about Chrome and Firefox I could not find any difference between static and dynamic canvas elements. Mainly the amount of pixels drawImage() handles makes it slow + the current globalCompositeOperation (copy, source-over are fastest). However, the browser has to render the full page, so it is a bad idea to place a stretched (background) image below the canvas.
There is a difference between the canvas attributes width/height and its style width/height attributes. You may have a 300*200 pixels canvas with a style size set to 100%. Then internal drawing speed is same what ever the browsers window size is. Of course display quality is a concern.
You may want to separate drawing (lines, boxes, arcs etc) from blitting (drawImage) and find out what consumes more time in your application. As long there is no need for multiple canvas (image processing, blending videos, etc.) try to avoid drawImage(). Your code - not elements - should help you to deal with 'organizational purposes'.
A fullscreen drawImage() on a 1 GHZ Netbook with 1024x600 pixels takes about 10msec. Doing it twice means there is no way to achieve a display rate of 50Hz. Things getting worse if you target iPhone or Android smartphones.
There is no need to do good-old-double-buffering with canvas, it's already implemented. You are free to update only relevant (dirty) subparts of your canvas element whenever you want and gain essential msecs.
Instead of using multiple canvas there is an option to do all invisible operations on a huge one in different sections - drawImage() with target and source the same. It is easier then to see what is happening while debugging.

Categories

Resources