fxCanvas is an implementation of the HTML5 Canvas element for Internet Explorer (two-dimensional graphics only).
Download package, unzip it into a public directory on the server and then paste in head section of the page following tags:
<head> <script type="text/javascript" src="/public/path/jooscript.js"></script> <script type="text/javascript" src="/public/path/fxcanvas.js"></script> <!--[if IE]><script type="text/javascript" src="/public/path/flash_backend.js"></script><![endif]--> <comment><script type="text/javascript" src="/public/path/canvas_backend.js"></script></comment> </head>
If you are not familiar with Canvas API, it may be useful to read this:
New! Images and text are now clipable.
fxCanvas also works properly with data:
URIs in Internet Explorer. Example.
fxCanvas supports almost all the Canvas features. The differences is in:
Invoke command and chaining operations
Context commands are keeping in a buffer before they will be applyed (IE only), so that to get values you have to use method invoke()
:
<script type="text/javascript"> var cv = document.getElementById("cv"); var ctx = cv.getContext("2d"); ctx.setFillStyle("#ff0") .setStrokeStyle("#0ff") .strokeRect(10, 20, 30, 30) .fillRect(30, 40, 50, 50) .invoke("getImageData", 0, 0, cv.width, cv.height, function (imageData) { // ... processing image data }); </script>Images
Prior to using images you have to preload them:
<script type="text/javascript"> var cv = document.getElementById("cv"); var ctx = cv.getContext("2d"); var image_src = "sample.jpg"; cv.onload = function(img) { if (img.src.indexOf(image_src) > -1) { ctx.drawImage(img, 10, 10); } } cv.loadImages(image_src /* ... img1, img2, ... imgX */); </script>Image data array
We cannot use canvas image data as it declared in specs, because of IE using extremely ineffective memory manager so it may eats all available memory in some circumstances. So that fxCanvas is using slightly different image data format.
Take a look at example:
<script type="text/javascript"> var cv = document.getElementById("cv"); var ctx = cv.getContext("2d"); ctx.invoke("getImageData", 0, 0, cv.width, cv.height, function(buf) { for (var i = 0; i < cv.width*cv.width; i++) { var pixelValue = buf.data[i], // pixel value is 32-bit integer red = pixelValue >> 24 & 0xFF, green = pixelValue >> 16 & 0xFF, blue = pixelValue >> 8 & 0xFF, alpha = pixelValue & 0xFF; // // exchange color channels buf.data[ofs] = (blue << 24) + (red << 16) + (green << 8) + alpha; } ctx.invoke("putImageData", buf, 0, 0, function(){ // ... print out the buffer after the operation will be completed console.log("Image data dump:" + buf); } }); </script>
Further explanation can be founded here.
isPointInPath()
isPointInPath()
in Internet Explorer returns true
if point in bounding box of the path. To get accurate results, use ctx.invoke("isPointInPath", x, y, ...)
.
toDataURL()
To get canvas shot you have to call the function with data handler:
<script type="text/javascript"> var cv = document.getElementById("cv"); var type = "image/jpeg", quality = .4; // quality is optional argument cv.toDataURL(type, quality, function (png_data) { // draw slice of the canvas on the same canvas at top right corner var ctx = this.getContext("2d"); this.onload = function (img) { ctx.drawImage(img, 0, 0, cv.width - 100, 0, 100, 100); } this.loadImages(png_data); }); </script>
Possible types: image/png
, image/jpeg
, .image/svg+xml
How-to create Canvas element in script
The simpliest way to dynamically create canvas element is:
<script type="text/javascript"> var cv = document.createElement("canvas"); cv.width = 200; cv.height = 100; document.body.appendChild(cv); // ... </script>
Note that if fxCanvas lib is loaded then in newly created elements will be using extended context by default. To disable this behavior and manually initialize extended context, use following code:
<script type="text/javascript"> $Import("buz.fxcanvas"); // don't forget to disable fxCanvas before page content will loaded fxcanvas.config.enable = false; window.onload = function(){ var cv = document.createElement("canvas"); fxcanvas.initElement(cv) // ... } </script>
Context and Backend
There are a few two-dimensional Canvas contexts: first is extended context canvas.getContext("2d")
, second is original context canvas.getBackend("2d")
. Use last one if you want native drawing speed.
Composite operations
Only source-over
and lighter
are supported.
Handling canvas resize event
There is a specific problem with canvas resizing due to asynchronous nature. You cannot draw graphics right after the canvas was resizing or it will be clear. As a solution I've added oncanvasresize
event which is fired when canvas will be ready after resize. Note that oncanvasresize
will not be triggered if the dimensions is the same or is changed style property.
<script type="text/javascript"> ctx.canvas.width = 400 ctx.canvas.height = 300 ctx.oncanvasresize = function(){ ctx.beginPath(); ctx.arc(75,75,50,0,Math.PI*2,true); ctx.stroke() } </script>
Text API
Text API is the most weak part. First is that transformed text looks awkward. Second is not supported method strokeText()
. But measureText()
returns even four values: width, height, ascent and descent (only for flash backend).
<script type="text/javascript"> ctx.font = "35px Arial" ctx.invoke("measureText", "abc", function(dim){ trace(dim.width, dim.height, dim.ascent, dim.descent) }) </script>
The things may change when I add a brand new text renderer.
Extended context (global extCanvasRenderingContext2D
) provides some new useful features for developers .
Animation
There are two ways to making animation on Canvas. First case is using setInterval()
, second case is using oncanvasframe
event:
<script type="text/javascript"> var ctx = document.getElementById("cv").getContext("2d"); /* * variant one */ setInterval(function() { // ... draw frame here }, 1000); /* * variant two */ ctx.canvas.frameDuration = 10; // in microseconds ctx.canvas.oncanvasframe = function(){ // frame event handler will fired with interval in 10ms // ... draw frame here }; // Warning: animations with complex graphics and tiny frameDuration value may hang on the browser! </script>
Using oncanvasframe
event is strongly encouraged, as in Internet Explorer animation running on setInterval()
will show incorrect frame rate. Besides in modern browsers (e.g. Firefox 4) animation will be play smoother on frame event (technically: synced with display refresh frame rate).
Note: oncanvasframe
event is non-standard extension.
Default frameDuration
is 100ms.
Canvas Path
Starting from version 0.2 is introduced a new experimental method for drawing complex curves. For that was added special interface CanvasPath
, which allow developers to create array of path segments. It make fast drawings in IE even with complicated curves thanks to caching algorithm. In other browsers using CanvasPath
will not give performance gain. To use this feature set ctx._useCanvasPath
or fxcanvas.config.useCanvasPath
as true
. By default useCanvasPath
is false
.
A very generic example:
<script type="text/javascript"> var cv = document.createElement("canvas"); var ctx = cv.getContext("2d") var longPath = ctx.createPath() longPath.moveTo(0, 0) for(var i=0; i<1000; i++) { longPath.lineTo(i, i) } ctx.beginPath() ctx.appendPath(longPath) ctx.stroke() ctx.rotate(90*Math.PI/180) ctx.beginPath() ctx.appendPath(longPath) ctx.stroke() </script>
Path bounds
There are some new methods and properties:
isPointInPathBounds(x, y) : boolean
getPathBounds() : Rectangle
transformMatrix
propertyInternally they are used as replacement for isPointInPath
in IE. To use these methods in another browsers other than IE, set ctx._tracePathBounds
or fxcanvas.config.tracePathBounds
property as true
. By default tracePathBounds
is true
for IE and false
for others.
These methods are available even if the flash is disabled.
<script type="text/javascript"> ctx.beginPath() ctx.rect(100, 100, 50, 50) var bounds = ctx.getPathBounds() trace(bounds.x, bounds.y, bounds.width, bounds.height) // will output 100 100 50 50 </script>
Basic geometry
JooScript provides some basic geometry primitives such as Point, Rectangle and Matrix2d. They can be used within extended context:
<script type="text/javascript"> $Import("geom.*") var p0 = new Point(10,10) var p1 = new Point(100,100) var rect = new Rectangle(20,10,300,300) var pointer = {x: 123, y: 45} ctx.beginPath() ctx.moveTo(p0) ctx.vectorTo(p1) ctx.rect(rect) ctx.stroke() if( ctx.isPointInPath(pointer) ) { // ... } </script>
Extended context also has transformMatrix
property which is a 3x2 transformation matrix. It is available only if tracePathBounds
is on.
For futher info refer to JooScript docs.
setInterval
. Use oncanvasresize
event as workaround. Here is an example.
Download zip or grab fresh trunk from SVN repo.
isPointInPath()
drawImage(canvasElement, ...)
drawImage(videoElement, ...)
;toDataURL("image/xml+svg")
;
Beta 4 (2011-02-05)
It seems basic Canvas API is implemented. I wonder is it ready for production?
jooscript.js
is updated to the latest beta with bright shiny new features.oncanvasframe
now based on new approach from Mozzila: mozRequestAnimationFrame
which gives pretty smooth playback for animations and games. Great introduction to mozRequestAnimationFrame
is here.canvas.loadImage
renamed to loadImages
as it handle multiple arguments.isPointInPath
(via ctx.invoke("isPointInPath", x, y, ...)
).Beta 3 (2010-12-25)
There are a lot of constructive changes and only a few new features.
oncanvasresize
event. Example.onframe
attribute renamed to oncanvasframe
.frameDuration
property for canvas backend.Beta 1 (2010-11-12)
x
height where element is pixel value encoded in 32-bit integer. Data structure comparison.drawImage([Canvas element], ...)
.createImageData()
;onframe
and frameDuration
;HTMLCanvasElement
and CanvasRenderingContext2D
in Internet Explorer;
Download source (don't forget to file an issue when you find something bad).