Activate your free membership today | Log-in

Monday, June 30th, 2008

ShiftZoom: Zoomify your oversize images

Category: Canvas, JavaScript, Library

ShiftZoom

ShiftZoom 1.0 is the latest tool from Christian Effenberger that allows you to add zoom and pan functionality to oversized images on your webpages. It uses unobtrusive javascript to keep your code clean. Requires no plugin/extension or any other external resource!

It works in all the major browsers - Mozilla Firefox 1.5+, Opera 9+, IE 6+ and Safari. Works also on older browsers supporting images & createElement & getElementById, else it'll degrade and your visitors won't notice a thing.

It is as simple to use as:

HTML:
  1.  
  2. <div><img onLoad="shiftzoom.add(this);" width="400" height="200" .../></div>
  3.  

Posted by Dion Almaer at 11:15 am
10 Comments

++---
2.9 rating from 30 votes

Tuesday, June 24th, 2008

Rendering performance in Canvas compared to SVG and VML

Category: Canvas, Performance

Just after I posted about Ernest's canvas experiment with photos he put something else up that tests the performance of rendering polygons with Canvas compared to other techniques.

The demo lets you run a live test, and view saved tests, comparing the Google Maps interface, which "currently draws polygons using VML for Internet Explorer, SVG for Firefox and image retrieval for Safari and Firefox linux."

Canvas Rendering Compare

At first the results were surprising. The canvas version was magnitudes faster. However, then they worked out that the live Google Maps version is actually doing a lot more than just drawing the polygons, that being said, a commenter had a valid point:

If we analyze the rendering time of the markup alone, both SVG and VML are not necessarily slower than canvas and canvas+excanvas.js. So the difference in performance is due to the implementation of polygons before the markup is output which the canvas implementation is skipping.

That doesn't make the experiment invalid. You didn't show that Canvas is faster than SVG or VML.
But you did show that it's possible to get much better polygon performance than the current API using a more direct to the metal approach - with whatever rendering engine. And people are crying out for faster polygons.

Posted by Dion Almaer at 8:59 am
11 Comments

+++--
3.8 rating from 23 votes

Monday, June 23rd, 2008

Photo Collages with Canvas

Category: Canvas

Canvas with Flickr

Ernest Delgado is having fun experimenting with canvas. He has posted on one of his tests which involved creating a photo-table-like system.

You can visit the demo that allows you to work with some photos and export them out. You can play with adding borders, show corners for rotation, all on the fly.

It is a rich example, and Ernest explained how he did it:

Implementing this in canvas presents two main challenges: drag & drop and performance. I tried several approaches to solving these problems, and ended up using a multilayer solution which renders only the active image on the top-most canvas layer. This allows us to have drag & drop without needing to redraw every image each time one of them is dragged.

You can check out the source code for yourself.

Ernest has some other fun things that he is playing with, which I hope to feature soon.

Posted by Dion Almaer at 7:49 am
8 Comments

++++-
4.5 rating from 30 votes

Thursday, June 19th, 2008

Algorithm Ink: Algorithm-driven Painting with Sharing and On-line Editing

Category: Canvas, JavaScript

John Resig linked to Aza Raskin's Algorithm Ink which is an implementation of the Context Free Art project in JavaScript using Canvas.

You can draw immediately with clicks, browse other art, and save your work. You can also edit the code to tweak it:

startshape scale

rule scale{
	SPIKES{ s .03 }
}

rule SPIKES {
	SPIKE {}
	SPIKE { r 90 }
	SPIKE { r 180 }
	SPIKE { r 270 }
}

rule SPIKE {
	LSPIKE {}
}
rule SPIKE {
	LSPIKE { flip 90 }
}

rule LSPIKE {
	SQUARE {}
	LSPIKE { y 0.98 s 0.99 r 1}
}
rule LSPIKE 0.005 {
	SPIKE { r 90 }
	SPIKE { r -90 }
	LSPIKE { y 0.98 s 0.99  r 1}
}

rule MOUSECLICK{
  SPIKES{ s .025 }
}

When I kicked it off in WebKit nightly, I got a nice "you aren't using a standards compliant browser" message, but it seemed to work fine ;)

Posted by Dion Almaer at 7:52 am
Comment here

+++--
3.2 rating from 5 votes

Wednesday, June 18th, 2008

Hypno trip down the fractal rug

Category: Canvas, JavaScript

Hypno trip

What a great title. It is an entry in the JavaScript 20 liners call out:

JAVASCRIPT:
  1.  
  2. //      chain( func )
  3. //      make func chainable by making it return itsReturnValue||this
  4. function chain( func )
  5. {
  6.         return function()
  7.         {
  8.                 return func.apply( this, arguments )||this;
  9.         }
  10. }
  11.  
  12.  
  13. //      initialize everything
  14. onload = function()
  15. {
  16.         //      initialize the contexts and the fractal
  17.         window.fx =
  18.         {
  19.             'barCtx':      document.getElementById('bar'      ).getContext('2d'),
  20.             'fooCtx':      document.getElementById('foo'      ).getContext('2d'),
  21.             'logicCtx':  document.getElementById('logic'  ).getContext('2d'),
  22.             'renderCtx':        document.getElementById('render').getContext('2d'),
  23.             'fractal':    [0,0,0,0,2,0,0,0,0],
  24.             CanvasRenderingContext2D:   (window.CanvasRenderingContext2D?CanvasRenderingContext2D.prototype:document.getElementById('bar'  ).getContext('2d').__proto__)
  25.         }
  26.  
  27.         //      set( what, to )
  28.         //      sets a property of the CanvasRenderingContext2D, making such operation chainable
  29.         window.fx.CanvasRenderingContext2D.set = function( what, to )
  30.         {
  31.                 this[what] = to;
  32.         }
  33.  
  34.         //      switchTo( context )
  35.         //      return another CanvasRenderingContext2D, making such operation chainable
  36.         window.fx.CanvasRenderingContext2D.switchTo = function( context )
  37.         {
  38.                 return context;
  39.         }
  40.  
  41.         //      chain a bunch of CanvasRenderingContext2D methods
  42.         for( chainThat in {set:1,switchTo:1,clearRect:1,save:1,translate:1,rotate:1,drawImage:1,scale:1,restore:1,fillRect:1,moveTo:1,lineTo:1,beginPath:1,closePath:1,stroke:1,fill:1,arc:1} )
  43.         {
  44.                 window.fx.CanvasRenderingContext2D[chainThat] = chain( window.fx.CanvasRenderingContext2D[chainThat] );
  45.         }
  46.  
  47.         //      let's get the party started
  48.         render();
  49. }
  50.  
  51.  
  52. //      render()
  53. function render()
  54. {
  55.         //      the time is now
  56.         var     now    = new Date().getTime();
  57.  
  58.         //      mutate the outer cells of the rug
  59.         fx
  60.                 .fractal[ Math.floor(Math.random()*8+5)%9 ] = Math.floor( Math.random()*3 );
  61.  
  62.         //      softly kills the previous generations of the rug
  63.         fx
  64.                 .fooCtx
  65.                         .set( 'fillStyle', 'rgba(0,0,0,.1)' )
  66.                         .fillRect( 0, 0, 192, 192 )
  67.                         .set( 'fillStyle', '#653' )
  68.                 .switchTo( fx.barCtx )
  69.                         .clearRect( 0, 0, 192, 192 );
  70.  
  71.         //      render 1st generation of the rug
  72.         for( var i=-1; i&lt;9; fx.fooCtx.fillRect( (++i%3)*64+1,Math.floor(i/3)*64+1,(fx.fractal[i]&1)*62,(fx.fractal[i]&1)*62 ))
  73.         {
  74.         }
  75.         //      render next generations of the rug
  76.         for( var j=0; j++&lt;3; fx.fooCtx.drawImage( fx.barCtx.canvas,0,0 ) )
  77.         {
  78.                 for( var i=-1; ++i&lt;9; fx.barCtx.drawImage( fx.fooCtx.canvas,0,0,192,192, (i%3)*64+1,Math.floor(i/3)*64+1, (fx.fractal[i]&2)*31, (fx.fractal[i]&2)*31 ) )
  79.                 {
  80.                 }
  81.         }
  82.  
  83.         //      render rotozoomed rug
  84.         fx
  85.                 .logicCtx
  86.                         .set( 'globalCompositeOperation', 'source-over' )
  87.                         .clearRect( 0, 0, 256, 192 )
  88.                         .save()
  89.                         .translate( 96, 96 )
  90.                         .rotate( (now/5841%2)*Math.PI )
  91.                         .scale( 1+2*((now/1274)%1), 1+2*((now/1274)%1) )
  92.                         .drawImage( fx.fooCtx.canvas,0,0,192,192, -288,-288,576,576 )
  93.                         .drawImage( fx.fooCtx.canvas,0,0,192,192, -96 ,-96 ,192,192 )
  94.                         .drawImage( fx.fooCtx.canvas,0,0,192,192, -32 ,-32 ,64 ,64  )
  95.                         .restore()
  96.                         .set( 'globalCompositeOperation', 'copy' )
  97.                 //      prepare for hypnoglow
  98.                 .switchTo( fx.renderCtx )
  99.                         .set( 'globalCompositeOperation', 'source-over' )
  100.                         .clearRect( 0, 0, 192, 192 )
  101.                         .drawImage( fx.logicCtx.canvas, 0, 0 )
  102.                         .set( 'globalCompositeOperation', 'lighter' );
  103.  
  104.         //      hypnoglow
  105.         for( var i=-1; ++i&lt;6; fx.renderCtx.drawImage( fx.logicCtx.drawImage( fx.logicCtx.canvas, 0, 0, 192>>i, 192>>i, 0, 0, 96>>i, 96>>i ).canvas, 0, 0, 96>>i,  96>>i, 0, 0, 192, 192 ) )
  106.         {
  107.         }
  108.  
  109.         //      here we go again
  110.         setTimeout( render, 25 );
  111. }
  112.  

Posted by Dion Almaer at 6:32 am
7 Comments

++++-
4.7 rating from 29 votes

Friday, May 9th, 2008

Processing.js: Port of the Processing language to JavaScript and Canvas

Category: Canvas, JavaScript

Processing.js

John Resig has completed 7 months of work to produce a port of Processing, the "programming language and integrated development environment (IDE) built for the electronic arts and visual design communities", which aims to teach the basics of computer programming in a visual context, and to serve as the foundation for electronic sketchbooks. One of the stated aims of Processing is to act as a tool to get non-programmers started with programming, through the instant gratification of visual feedback."

Processing.js uses Canvas and obviously JavaScript to get the job down in the browser.

John talks about the two pieces of the puzzle:

The Processing Language

The first portion of the project was writing a parser to dynamically convert code written in the Processing language, to JavaScript. This involves a lot of gnarly regular expressions chewing up the code, spitting it out in a format that the browser understands.

The language includes a number of interesting aspects, many of which are covered in the basic demos. Here's a brief selection of language features that are handled:

  • Types and type casting - Type information is generally discarded, but becomes important in variable declaration and in casting (which is generally handled well).
  • Classes - The full class system is supported (can be instantiated, etc. just fine).
  • Method overloading and multiple constructors - Within classes you can have multiple method (or constructor) definitions - with the appropriate methods being called, based upon their signature length.
  • Inheritance - Even classical-style inheritance is supported.

Note: There's one feature of Processing that's pretty much impossible to support: variable name overloading. In Processing you can have variables and functions that have the same name (e.g. float size = 0; float size(){}). In order to support this there would have to be considerable overhead - and it's generally not a good practice to begin with.

The Processing API

The second portion of the project is the full 2d Processing API. This includes all sorts of different methods:

  • Shapes drawing
  • Canvas manipulation
  • Pixel utilities
  • Image drawing
  • Math functions
  • Keyboard and mouse access
  • Objects (point, arrays, random number generators)
  • Color manipulation
  • Font selection and text drawing
  • Buffers

Congratulations to John, and I look forward to seeing some fantastic visualizations in the browser thanks to this work.

Posted by Dion Almaer at 12:54 am
10 Comments

++++-
4.6 rating from 37 votes

Monday, May 5th, 2008

Compression using Canvas and PNG

Category: Canvas, JavaScript

The image above is the 124 kilobyte Prototype library embedded in a 30 kilobyte 8 bit PNG image file.

Jacob Seidelin had some fun this weekend it appears and created a script that can read in JavaScript code from images. To do this, he used the canvas getImageData() method.

Here are the detailed steps:

The first step was to find the best image format for the job, that means the one that gives the best compression while still being lossless. Here on the intertubes, we don't get a lot of image format choices and since JPEG is lossy, we're down to GIF and PNG.
For PNG we have two options, 24 bit and 8 bit. Using 24 bit RGB colors, we can store 3 bytes of data per pixel while 8 bit indexed colors only gives us 1 byte per pixel.
A quick test in Photoshop tells us that a 100x100 image with random 24 bit colored noise compresses down to about 20 KB while a 300x100 image with random 8 bit monochromatic noise compressed down to just 5 KB. A regular 8 bit GIF comes in a bit heavier than the 8 bit PNG, so we go with the PNG option.

Now we need to convert our Javascript file into color data and stuff it in a PNG file. For this purpose, I crafted this quick and dirty PHP script, which reads the Javascript file, creates a PNG image file and simply lets each pixel have a value 0-255 corresponding to the ascii value of the character in the script.

I ran into a problem here, since the image is created as a truecolor image and we need it to be 8 bit indexed and PHP won't make an exact conversion. I guess there are ways to create a palletted image from scratch in PHP/GD, but I haven't looked into that yet. The solution for now is to simply run the generated image through something like Photoshop and convert it to 8 bit there.

So now we have the Javascript all nice and packed up in a compressed PNG file and now we need to get it out again in the client. Using the canvas element, we simply paint the picture using drawImage() and then read all the pixel data using getImageData(). This data is given to us as a large array of values, where each pixels takes up 4 elements (RGBA), so we just take every 4 value and tack them all together into an eval()-ready string. And we're done.

And the reading function is here.

NOTE: This is for fun, and isn't meant to be used in the real world. That being said, see it at work in the mario game.

Posted by Dion Almaer at 10:28 am
20 Comments

++++-
4.9 rating from 32 votes

Thursday, April 24th, 2008

Using canvas to test your site with colorblind folk

Category: Accessibility, Canvas, Library

Color Matrix

The picture above is showing you how someone with the color blindness trait Tritanopia would see the image. Michael Deal first created the Color Matrix Library, which supports a large portion of the most common color functions available, including:

Hue, Saturation, Brightness, Contrast, Exposure, Temperature, Tint, Channels, Blindness, Colorize, Threshold, and Invert

Michael then created a canvas library that uses the Color Matrix to help us visualize what our content may look like to people who have various color blind issues. Here is what he did:

The most obvious way would be to do the calculations in CIE XYZ using confusion lines, however, <canvas> uses RGB. So you’d have to convert from XYZ to RGB, run the confusion lines, then convert back to RGB. Here’s an example of what that looks like: Color Blindness Library — It’s great for running on a few colors, but too slow for larger images.

Matrix’s are generally about as quick as you’re going to get for generic color filters, so that’s what I’ve converted the formulas into – compliant with Actionscript’s ColorMatrix, and other programming languages that use standard RGBA matrix’s. Also, I’ve converted them into color transform’s which are useful in Actionscript (ColorTransform), Pixelmator (Image... Channel Mixer), and Photoshop (Image... Adjustments... Channel Mixer).

I used data generated by Matthew Wickline’s formulas to base my blindness library. My script triangulates the hue by comparing the un-filtered, completely saturated, RGB values with the same value after they’d been run through Wickline’s formula.

Posted by Dion Almaer at 1:35 pm
5 Comments

++++-
4.5 rating from 22 votes

Wednesday, April 16th, 2008

Busy.js: Loading indicators with Canvas

Category: Canvas, JavaScript, Library

Busy.js Logo

Christian Effenberger is back with some more canvasy goodness. He has released Busy.js, a library that allows you to add/remove loading indicators to html elements on your webpages (inc. overlay color & transparency). It uses unobtrusive javascript to keep your code clean. Requires no plugin/extension or any other external resource.

Usage

JAVASCRIPT:
  1.  
  2. var ctrl = getBusyOverlay(document.getElementById