Friday, February 25, 2011

Canvas vs. SVG...?

Hi again,
today i would like to share some thoughts about HTML5 canvas and svg with you. It seems that not everybody understand that the new capabilities of HTML5 support for canvas and svg does not mean that we have to decide which is the better technology in general. You just have to choose the right tool for your job...if you have to handle a lot of dead bitmaps without any or just a few interactions you should take a look at canvas and if you need the full dom accessibility and living dom objects you should take svg.
I played around with svg around 2004 and at this time the support was bad (unfortunately). But with todays browser support for svg i thought about combining canvas with svg. 
The idea is to use images that has been generated in canvas and use them as background images for svg animations. In this specific case i asked myself if it would make sense to create the static drawing parts of a gauge (like the background and the foreground) in canvas and put an animated svg pointer in between these images and let svg do the animation instead of a javascript. So the question was how to get a canvas as an image and the easy answer is you have to use the toDataURL("image/png") method on a canvas element. This will create a base64 encoded image in png format that one could use in an svg <image> element.
So i added two functions to the canvas component that returns the backgroundimage and the foregroundimage by using the toDataURL() method. 

// Return a base64 encoded image of the background for svg use
this.getBackgroundImage = function()
{
    init();
    return BACKGROUND_Buffer.toDataURL("image/png");
}  

When this was done i just have to add the image via javascript to the svg element in my html body and the images will be painted by svg instead of canvas.

// Add the canvas as backgroundimage to the svg container
var backgroundImage_dataurl = compass.getBackgroundImage();
// Create a new <image> tag in the svg element with the canvas as a source image
var svg_BackgroundImage = document.createElementNS("http://www.w3.org/2000/svg", "image");
svg_BackgroundImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", backgroundImage_dataurl); 
svg_BackgroundImage.setAttribute("id", "background");
svg_BackgroundImage.setAttribute("width", IMAGE_WIDTH); 
svg_BackgroundImage.setAttribute("height", IMAGE_HEIGHT); 
svg.appendChild(svg_BackgroundImage);    

Now i had to add the pointer to the svg element between the background image and the foreground image via javascript which could be done by using the svg <path> element. 

// Add the svg pointer ontop of the image
var northPointer = document.createElementNS("http://www.w3.org/2000/svg", "path");
northPointer.setAttribute("id", "northpointer");
northPointer.setAttribute("width", IMAGE_WIDTH);
northPointer.setAttribute("height", IMAGE_HEIGHT);
var northPath = "M" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5280373831775701 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.14953271028037382 +
         "L" + IMAGE_WIDTH * 0.4719626168224299 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "Z";           
northPointer.setAttribute("d", northPath);
northPointer.setAttribute("stroke", "darkred");
northPointer.setAttribute("fill", "red");
svg.appendChild(northPointer);

To add an animation (in this case from 0 to -360 deg in an infinite loop) to the pointer i decided to use the <animateTransform> element of svg and added it to the svg element via javascript. 

// Animate NorthPointer
var svg_animateNorth = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
svg_animateNorth.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#northpointer");
svg_animateNorth.setAttribute("id", "animatenorth"); 
svg_animateNorth.setAttribute("attributeName", "transform");
svg_animateNorth.setAttribute("begin", "0s");
svg_animateNorth.setAttribute("dur", "3s");
svg_animateNorth.setAttribute("type", "rotate");
svg_animateNorth.setAttribute("from", "0 100 100");
svg_animateNorth.setAttribute("to", "-360 100 100");
svg_animateNorth.setAttribute("repeatCount", "indefinite");    
svg.appendChild(svg_animateNorth);    

And that's it, now i could compare pure javascript canvas animation with svg animation...

To see the page in action please click on the link below the image.

Click to see it in action...

The canvas animation will work in nearly all non ie browsers but the svg animation seems to have problems with webkit based browsers which means you won't see the right side moving in Chrome and Safari. But it will work in FireFox 4.

So keep coding...



Friday, February 18, 2011

Friday Fun (Canvas) Component VI

Back from JFokus (which was great by the way) i have some more fun to share with you today. This time it's related to HTML5 canvas (what else ;-)).
Sitting in a talk at JFokus i've got the idea to convert the compass component of the SteelSeries Swing library to canvas to use it in conjunction with the HTML5 geolocation api (e.g. position.coordinates.heading). 
It tooks me several talks and coffee breaks to complete the conversion and here is the result...



Because it's part of the steelseries canvas version one could define things like frameDesign, backgroundColor and pointerColor.
Unfortunately the geolocation api did not work out as well which was the reason to convert another component from the SteelSeries Swing library.
I'm talking about the level component. I read that there is a deviceorientation api in the html5 spec (draft) which i might use also on my macbook pro so here is the result of the level component...


And again you could set the frameDesign, backgroundColor and pointerColor of the component in the constructor of the component.
Well looking at a static image is fine...but better is to see it in action. To get there, please click at the link below the following image...

Click to see it in action...
Well that's better right...? But only driven by some setInterval() calls to a method that creates random values. Would it not be nice to get a direct response of an inbuild sensor...YES !!!

So for all running on windows, linux, android....sorry guys, the following link will only show you a static components. But if you are running a device like a Macbook, Macbook Pro, iPad (iOS 4.2), iPhone4 (iOS 4.2) or iPhone 3Gs (iOS 4.2) you should see  the level component rotating if you rotate your device. I only had the chance to test it on my Macbook Pro and it works if you tilt the Macbook Pro to the left or right.
Just test it by clicking on the link below the following image...

Click to see it in action...
That's it for today and even if it's not Java related i hope it will be fun for one or the other...

Cheers and keep coding...


Update:
As i learned today, the device needs a gyroscope to fire onDeviceOrientation events which excludes iPads and iPhones 3Gs from the list. That means you could only see the level component on an Macbook, Macbook Pro and iPhone4. I extended the page by a compass and a speed gauge that will show the direction and the speed when you move with your device (e.g. in a car). In this case it will work also on Android devices with os version >= 2.2.

Friday, February 11, 2011

Friday Fun Component V

It's friday again...which means it's time for some fun...

Last wednesday at the Java Roundup of the Java User Group Muenster i decided to create a little fun component again.
Every morning on my way to the office i see one of the following traffic signs and what should i say...i like it somehow...



So i asked myself if it would be hard to create something like this in Swing. 
The first idea was to only create this single sign but after a few more days passing by the traffic sign the idea came to my mind that it would be fun to load some image, scale it to the number of led's in the sign and create the led's with the appropriate color of the image pixels.
But let me give you a more detailed description of what i've done...

These are the steps it takes to create the component:
  1. Create a panel of 250x250 px
  2. Fill the panel with led components of a fixed size (10x10 px) with a rasterStep of 6 px (this is the distance between each led in x and y direction).
  3. Now you could load an image into the component via the setSymbol(fileName) method.
  4. The image file will be loaded, scaled to the size of the raster (no. of led's in x and y direction).
  5. Get the color of each pixel in the image and set the related led in the raster to the same color.
  6. If the brightness of the pixel is smaller than 50% the color of the led will be set to black and it will be switched off.
  7. Draw all the led's in a buffered image and draw the image to the panel.

To create a traffic sign like the one on the image above i created a little png file that looks like this...


This image has the size of 41 x 41 px which is exactly the number of led's that i have in the default raster (ImageWidth / rasterStep => 250px / 6px = 41.666 => 41). I do not use antialiasing in the image because every pixel in the image should be represented by one led in the raster later on. You could vary the rasterStep variable (distance between the led's) in a range of 5...10 px.

And this is the result after i load the image into the component...


Looks not too bad...

You can imagine that it takes some time to create all the led objects and set them to the right color (set the color will create a new led image with the selected color). So this component is not very "fast" but that was not the intention. 
It's really just a quick hack to get the idea out of my head and has nothing to do with production code etc...
The component is ideal to visualize monochrome icons or symbols that are not too big (because they will be downsized to the raster size).

Here are some more images i created...





I have no idea if this is of use for someone but if you would like to have the code...no problem...here we go, as always as a netbeans project:

    Source: FridayFunV_Source.zip

    Binary:  FridayFunV.zip

So enjoy the upcoming weekend and keep coding...


UPDATE:
Modified the file a bit in the way that it caches the led's which leads to a bit better performance...

Tuesday, February 8, 2011

SteelSeries 3.7 (ReUnion release)

Hi there,
The next version (3.7 3.7.1) of the SteelSeries library is released (please find it on Maven Central here). I call it the reunion release because from this release on you will also find the components from the SteelExtras lib back in the SteelSeries lib.
I split them off in the past because of the library size but figured out that it's much better to have all the components in one place (sorry for the inconvenience).
That means you will find the following components now also in the lib:

Altimeter, Clock, Compass, Radar, Level and Led





These components are placed in the eu.hansolo.steelseries.extras package.

The 3.7 3.7.1 release contains a lot of modifications and addons that i'll describe to in this post, starting with a new component...the SparkLine component...

A sparkline is a type of information graphic characterized by its small size and high data density (wikipedia). The term sparkline was proposed by Edward Tufte for small high resolution graphics embedded in a context of words, numbers, images etc.

The decision to add a sparkline to the library took me some time because i was not sure if this is really usefull but when i was doing some long term temperature measurement i found it might be really nice to see a graph of the values measured e.g. in the last hour etc.

So i added the sparkline component to the lib but i have to say that i created the sparkline only with visualizing measured data in my mind...means i have no idea if it is usable for other data like financial data etc. My implementation of a sparkline uses a so called timeframe (default is set to 1 hour == 3600 sec == 3600000 ms) and each value will be stored with the current timestamp. 
If the the list is "full", the first value in the list will be removed with every new value added to the end of the list. That means this sparkline only shows the number of values that was measured in the given timeframe. The timeframe is defined in milliseconds.


Here we go...

As you can see the sparkline component in the steelseries lib uses the same background as the lcd component. My idea was to add it to the gauges in a future release so that one could switch between the lcd display and the sparkline display.
The sparkline supports the following statistic data:
  • first Quartile Q1 
  • second Quartile Q2 (also known as Median) 
  • third Quartile Q3 
  • average 
  • variance 
  • standard deviation
If you need more information about these values please take a look at wikipedia.

The sparkline itself could be smoothed by using one of the following smoothing functions:
  • continuous average smoothing
  • cubic spline smoothing
  • hermite smoothing
  • cosinus smoothing
The smoothing could also be disabled which will show the real measured values.
Here is an example of the different smoothing functions...


Because the sparklines in the above example only contains a few values the result looks quite similar. If the smoothing is switched off it is possible to show the hi and lo value by a small indicator. If you only would like to see the sparkline itself without the colored background...just switch it off and you will get something like this...

As you could see on the image above, it is also possible to fill the area below the sparkline with a gradient. There is a default gradient where you only can define the base color which will fade out from top to bottom but you could also define the topAreaColor and the bottomAreaColor with it's alpha values and it will use your colors to fill the area. Here is another example of the filled area...

The sparkline component was built to visualize measured data (e.g. from a sensor) in a given timeframe (e.g. 1 hour) where you added the measured values every second. I hope it will be of use for someone...

In the 3.7 3.7.1 release of the lib i added a lot of small things like two new lcd colors...


But that's not all...i also added the possibility to customize the lcd colors. That means if you choose CUSTOM as your lcdColor, it will take the customLcdBackground paint (java.awt.Paint) to fill the background and the customLcdForeground color (java.awt.Color) to fill the lcd text. With this you might want to change the lcd colors to the creepy pink in the example...

Well talking about customizing leads me to the next customizable feature...the frameDesign. It follows the same rule as the lcd which means if you select CUSTOM as your frameDesign, it will take the paint object that is defined in customFrameDesign to fill the frame of your gauge. For example if you would like to add your own linear gradient to the frame...


But when i was playing around with gradients i figured out that it might be nice to add a little pseudo 3d effect to the frame and voila...here it is...


That means you could simply switch on frame3dEffectVisible and it will add a little overlay to the frame that creates the effect in the image above.
This will also work on the existing frame designs. This also means that if you simply put a plain color as your customFrameDesign and switch on the 3d effect you will get a more realistic look of your gauge.

Hmm...when talking about pseudo 3d effects i also have to mention the similar effect that is available for the sections feature. I was asked if it would be possible to add some kind of gradient to the sections and what should i say...yes it is and here is what it looks like...


This effect is only available in the standard radial gauge and only to the sections and not to the track. You could switch it on with section3dEffectVisible = true.

If you reduce the size of the gauge so that the size is only around 80px you will figure out that the pointer is hard to identify because it get's too small. That was the reason why i added another pointerType to the radial gauges (TYPE4). The idea came to me because Rémy Rakic sent me an image of gauge which uses a big pointer...so thanx Rémy...


And again i added the ability to customize the color of the pointer. That means if you select CUSTOM as pointerColor it will use the color (java.awt.Color) that is defined in customPointerColor to create the colors that will be used for painting the pointer. In addition to the new pointerType i also added a bigger knob which could be switched by using the property knobType.

Another modification/addon are the new foreground types for the radial gauges. Instead of using only one foreground you could now choose between three...


On the image you see the FG_TYPE1 on the left, FG_TYPE2 on the middle and FG_TYPE3 on the right side. Please use the foregroundType property to switch between them.

The last thing i would like to mention in this post is the ability to use a custom color for the led i'm using in all the gauges. Again if you choose CUSTOM as ledColor it will take the hue of the color that is defined in customLedColor to create the colors for the led. This makes it also possible to create a white led if you wish...


The custom ledColor could be defined in all gauges that support a led and also in the standalone led component from the extras package that you see on the image above.

I think that's it with the news, so if you would like to download the binary, please find it here:



I hope all these modifications are usefull for one or the other of you...

Cheers and keep coding...


UPDATE:
Release 3.7.1 of the library already because there was a problem with the resizing logic.