nooshu - Matt Hobbs' Web Development Blog

Kneeling on the shoulders of giants

Category: Experiments

I’m constantly thinking of little projects to be working on to expand my knowledge and skill-set, posts relating are filed here.

Recreate iPhone Swipe Effect using jQuery

Being a PC user for as long as I can remember it pains me to say this; if there’s one thing Apple does well it’s the User Interface (UI). When the iPhone was first released it really shook up the mobile market, with a touch screen interface and a tonne of applications to expand its functionality, it forced the other mobile phone manufacturers to play catch-up.

Something that comes naturally when you start to use the iPhone is the swipe between screens, allowing you to quickly view all your different applications. Just out of interest I decided to recreate this effect for the web using jQuery. Is it of any use to anyone? I doubt it, as it isn’t very natural to swipe using the mouse (unless you’re used to using mouse gestures). But I enjoyed putting it together.

If you swipe left/right toward a panel that doesn’t exist, it simply bounces back. The same goes for small mouse movements; the full animation will only occur when you swipe over a third of the width of a panel. View a demo.

Update: As requested by Matias I’ve added an indicator to show the total number of panels and the currently selected panel.

Update 2: I’ve uploaded a ZIP file here containing all the code used.

Update 3: For those of you who hate how the text is sometimes selected on drag (I do), you may want to take a look at this thread from Stackoverflow for a potential solution.

Mandelbrot Renderer Update

Since my recent blog post on my Mandelbrot set renderer using JavaScript and Canvas I’ve been made aware of an extremely useful method to add image data to a canvas context; the putImageData() method. Thanks to Kevin Pickell for pointing this out, he made use of it in his own Mandelbrot renderer.

So I decided to update my renderer to use putImageData as it’s much quicker than drawing each pixel straight onto the canvas. Usage is simple:

1
2
3
4
5
6
7
8
9
10
11
//Grab our canvas and context
var canvasID = document.getElementById("canvasID");
var context = canvasID.getContext('2d');

//Create an empty image data object
var imageDataObject = context.createImageData(width, height);
   
//Add our image data to the object
imageDataObject.data = imageData;
//Draw our image
context.putImageData(imageDataObject, 0, 0);

I found the way the imageDataObject expected data quite surprising at first; I think I was expecting an array of objects or an array of arrays, one for each pixel, but it expects a single large array with the red, green, blue and alpha value of each pixel in the canvas:

1
2
3
4
5
//Empty array
var imageData = [];
//For each pixel (top left to bottom right moving horizontally)
imageData.push(red, green, blue, alpha);
//Result: [r1, g1, b1, a1, r2, g2, b2, a2, r3....]

The advantage this method has is you calculate all your image data first, then pass it to the canvas. Before I was calculating a whole vertical row and drawing onto the canvas, before moving onto the next. Not at all ideal when you are repeating the process 600+ times.

Updating the non Web Workers version improved the render time by around 20 – 25 seconds! See the v2 version here. Unfortunately there were issues rotating the canvas after using putImageData(), no matter what I tried, the rotate() method seemed to be ignored, so I removed it. Maybe it’s a limitation of the method, but i’m still looking for a solution.

I had another surprise when adding the new draw method to the version using Web Workers (not fully functional). Since the worker simply needs to process the image data then pass it back to the window I assumed there wouldn’t be an issue; but that wasn’t to be. When letting the worker thread do the calculations it was taking around 8 seconds (initial render) to do this, where as in the main window it was taking less than 1 second. The time increased even more as you zoomed in:

  • Initial render: ~8000ms
  • +1 zoom: ~12000ms
  • +2 zoom: ~20000ms
  • +3 zoom: didn’t render

I have yet to find a solution to this issue; I’m guessing it may be some sort of worker thread priority or the way worker threads handle nested loops with calculations. Maybe a calculation rounding issue? If anyone has any ideas leave a comment.

Mandelbrot Set Renderer using JavaScript and the Canvas API

A couple of weeks ago I happened to notice a tweet on Twitter by Christian Heilmann who linked to Geoff’s Mandelbrot Renderer. Geoff has created a tool that renders the Mandelbrot set using JavaScript and the Canvas API… amazing! I’ve been interested in fractals for a good few years but have never had the chance to look into generating them; so I decided to have a play with Geoff’s version and see what I could come up with.

The Mandelbrot set was named after Benoit Mandelbrot, who first saw the shape at IBM’s Thomas J. Watson Research Centre on March 1st 1980. It’s place is in a field of mathematics called complex dynamics, having not looked at any mathematics for a good few years it took me some time to get my head round exactly what was going on, and I still only have an inkling of what it all means.

Various forms found in the Mandelbrot Set

Here are just a few of the shapes I found using the tool. Why not try it yourself?

The image above – top left is arguably the most famous fractal; the three other shapes have been generated by zooming into the original fractal. The ‘image’ has infinite resolution, you can keep zooming in and it will always generate a new image. I’d say the only limitation is the browser / computer generating it.

One thing you will notice when zooming is the fact the Mandelbrot set is self-similar (or at least close to self-similar). At many points you will notice the original fractal shape, only on a smaller scale. This along with other repeating shapes creates a beautiful image purely generated by mathematics.

Note: Slight update to the render method here.

View a demo here. A few features I added:

  • Add render loader and restyled the form layout
  • User can switch between colour & grey-scale
  • Ability to select a range of hues the render uses
  • Possible to change the saturation and lightness of colours used
  • Ability to rotate the canvas
  • Change the width and height of the render area
  • Select from a set of zoom / position presets
  • A version using the Web Workers API in Firefox 3.5+ (See notes below on usage)

Note: As I mentioned above I have created a version using the Web Workers API found in Firefox 3.5+, but I strongly recommend using the standard version; I created it to see what difference it would make to the render time.

As it is, it makes no difference, in fact it actually makes it worse. The iteration calculation has been offloaded to a worker thread, the worker compiles the data then sends it back to the window. The window then loops through this the data and renders the image since worker threads don’t have access to the DOM for security reasons. This rendering tends to slow the browser down making the UI very slugish. I’ve tried not to use a setTimeout(“function()”, 0), to allow the JavaScript engine to catch up as, but it looks like I may have to in future versions. View a version using the Workers API here.

Big thanks to Geoff for putting the original together. Sliders and event handling was added using jQuery and the excellent jQuery UI. Preview carousel function used jCarousel.

jQuery Plug-in: Simple Navigation Animation Stagger

It’s great when you run into old code that you’d completely forgotten about. While reviewing a couple of old sites I’d put together I ran into some old jQuery animation code the client had requested. I’ve used it on a couple of projects in the past, not always on the navigation; it can be used with any set of list items. So I popped it into a jQuery plug-in for quick deployment on future projects. View a demo or download.

jQuery.staggerNaver simply delays each fadeIn animation on a set of list items to create a type of ‘wave’ effect. The plug-in can accept an object with custom user settings:

1
2
3
4
5
6
7
8
9
//Plug-in usage
jQuery(function($){
    $("#ourULorOL").staggerNaver({
        animateTime: 150,
        easing: "swing",
        onePageOnly: false,
        onePageSelector: "#home"
    });
};
  • animateTime: Time taken for fadeIn animation in milliseconds (default: 210)
  • easing: Easing method used, requires the easing plug-in if not default (default: “swing”)
  • onePageOnly: Use only on one page e.g. your home page (default: false)
  • onePageSelector: If you are only using the animation on one page, what selector would identify to jQuery that you are on that page? (default: “#home”)

I’ve included the one page only setting because as with any set of page animation it can sometimes become very annoying, especially if it does it on every page load!

View a demo or download (version 0.1 – updated 25th Feb 2010).

jQuery Plug-in: Scalable Background Image

A few days ago a friend approached me about an interesting background effect he has seen on a website and how he wanted to implement it into his website. I was curious about how it worked so decided to build a jQuery plug-in that does it for you; hooray for jQuery (again).

The effect is a scalable background image; as you expand / contract the browser window the background image scales up and down with respectively. Unfortunately it isn’t possible to do using only CSS 2.1; it’s possible using CSS3 using the background-size property, though not yet widely supported. The technique doesn’t use a background image, it uses an absolutely positioned image to achieve the same effect; so it could be considered a hack. If you’re not sure what I mean, here’s a demo. It’s quite simple to use; here’s the basic HTML:

1
2
3
4
5
6
<div id="container">
    <!-- Content here -->

    <!-- This Image will resize with every window resize -->
    <img id="imageID" src="images/our-image.jpg" alt="Fake background image" >
</div>

The plug-in is called using (with custom settings):

1
2
3
4
5
6
7
8
//Plug-in usage
jQuery(function($){
    $("#container").backgroundScale({
        imageSelector: "#imageID",
        centerAlign: true,
        containerPadding: 100
    });
});

The plug-in accepts an object as an argument with custom user settings:

  • imageSelector: The ID or class of the fake background image (default: “#bgImage”).
  • centerAlign: Align the image in the center of the container, both vertically and horizontally (default: true).
  • containerPadding: Padding in pixels that expands the image slightly in relation to it’s container to minimise seeing behind the image when scaling up and down in certain browsers (default: 80).

A couple of things to note:

  1. You must have a container div for the image, using the body tag returns strange results.
  2. The resize event in Firefox is a little weird, it doesn’t fire continuously as you scale up and down so you can sometimes see the container background when scaling. There are plug-ins that make the resize event consistent across browsers.
  3. Since this is a JavaScript dependent effect it may be worth adding the fake background image using JavaScript
  4. It’s better to use a larger image for scaling, as expanding a smaller image will look fuzzy and out of focus.

Any questions / ideas for expanding this plug-in then leave a comment. View a demo or download (version 0.1 – updated 17th Feb 2010).

Currently on page 6 of 6« First23456