rotate360 (Image rotation in javascript)

This is an example of image rotation and control using CSS sprites and JavaScript. The example i went for is based on a product demo by apple for the Ipod touch. There example uses Quicktime but i thought is was possible in JavaScript so i gave it a go.

Space carousel

View Demo

Step 1

First i download the QuickTime file opened it and exported it as JPEG images at 1 image per second. I think this produced about 72 images at 40k each.

Step 2 – FAIL!

In my first attempt i tried to show all 72 images positioned on-top of one another. When i needed a specific image I would just change the z-index. The method stank and the results were terribly slow.

Step 3 – RSI!

My next idea was to use it as a CSS sprite. I had no idea this would work but set out adding all 72 images into one very large file. I even thought of writing an app just to do this for me as it may have taken less time. Once done the image dimensions were 880px by 33840px – The problem with this is I couldn’t save it as JPEG/png/gif only TIFF which isnt natively supported in browsers. So… I did some research and found out the height must be less than 30000px to be a JPEG. Once resized and saved i was ready to code.

Step 4 – code!

The coding was simple really: i just change the background position on mouse-move and the animation is done. Take alook at the code on the demo, it’s really easy. I added a few options just in case your using a slow browser or your CPU is slow.

Step 5 – Future work

I really like the effect and might see if speed improvements can be made in canvas. I might also invest in a tri-pod and lightbox and take some stop-motion pictures of my own. I have done a few websites where this would have been great. Any further suggestions please leave them below.

Spacegallery – mooStyle

I was combing the JavaScript framework blogs and came across this image carousel in JQuery: SpaceGallery. I used this same concept in my old website but it was written in mootools. The jQuery plug-in feels unresponsive and slow and doesn’t have any features. So here is the mootools version I wrote, sorry it is not as a plugin but feel free to make it into one.

Space carousel

View Demo

Things you need

First get Mootools (This demo uses 1.2.4) and if you want the color plugin I use in the demo you can download this from mootools more.

The JavaScript

Sorry about the mess of this: I haven’t written it to be dynamic as it was rushed out late at night. The positioning of elements is hard-coded but would be simple to adapt if i could be bothered to comment anything. So here it is:

var spacers = "";

function loadDemo(){
     spacers = $("spaceMan").getElements(".spaceOB");
     intSpace();
}

function intSpace(){
     spacers.addEvents({
          'mouseover': function(){
               if(this.getStyle("z-index") != 20){
                    this.setStyle("top", parseInt(this.getStyle("top"))-2);
               }
          },
          'mouseout': function(){
                if(this.getStyle("z-index") != 20){
                     this.setStyle("top", parseInt(this.getStyle("top"))+2);
                }
          },
          'click': function(){
               doSpace(this);
          }
     });

     spacers.each(function(item, index){
          var color = [index*40, 82, 87].hsbToRgb();
          spacers[index].setStyles({
               "z-index": 20-index,
               "background-color": color
          });
          spacers[index].set(
               'morph',
               {
                    duration: 1000-(index*100),
                    transition: 'Sine:out'
               }
          );

          spacers[index].morph(
          {
                opacity: [0, (100-(index*10))/100],
                width: 323-(index*32.3),
                height: 203-(index*20.3),
                left: 60+((index*23.5)/1.5),
                top: 80-(index*(15-(index)))
          });
     });
     setTimeout(function(){$("spaceHelp").fade([0,1]);}, 1000);
}

function doSpace(el){
     $("spaceHelp").fade(0);
     var positionOfClicked = 20 - el.getStyle("z-index");
     var topPos = 0;
     spacers.each(function(item, index){
          var zIndexi = parseInt(spacers[index].getStyle("z-index"));
          if(zIndexi == 20){
               spacers[index].setStyle("z-index", 20-(spacers.length-1));
               spacers[index].set('morph', {
                    duration: '500',
                    transition: 'Sine:out',
                    onComplete: function(){
                         spacers[index].set(
                              'morph',
                              {
                                   duration: '500',
                                   transition: 'Sine:out'
                              }
                         );
                         spacers[index].morph({
                              opacity: [0, 0.5],
                              width: [94,161.5],
                              height: [50, 62.5],
                              left: [170, 138],
                              top: [40, 30]
                         });
               }});
               spacers[index].morph({
                    opacity: 0,
                    width: 400,
                    height: 220,
                    left: 25,
                    top: 110
               });
          }
          else{
               var thisPos = 20-(zIndexi+1);
               spacers[index].setStyle("z-index", zIndexi+1);
               spacers[index].set(
                    'morph',
                    {
                         duration: '500',
                         transition: 'Sine:out'
                    });
                spacers[index].morph({
                     opacity: (100-(thisPos*10))/100,
                     width: 323-(thisPos*32.3),
                     height: 203-(thisPos*20.3),
                     left: 60+((thisPos*23.5)/1.5),
                     top: 80-(thisPos*(15-(thisPos)))
                });
          }
     });
     if(positionOfClicked == 0){
          return false;
     }
     if(positionOfClicked != 1){
          setTimeout(function(){doSpace(el)}, 125);
     }
}

The CSS and HTML

The css:

 #spaceManHolder{
   	width: 450px;
 	height: 500px;
 	margin: 40px auto 0px auto;
 	position: relative;
 }
 #spaceMan{
  	width: 450px;
 	height: 300px;
  	position: relative;
 }

 #spaceHelp{
 	font-size: 10px;
 	color: #fff;
 	text-align: center;
 	opacity: 0;
 }

.spaceOB{
	position: absolute;
	width: 100px;
	height: 100px;
	z-index: 100;
}

and the html:

<div id="spaceManHolder">
     <div id="spaceMan">
          <div class="spaceOB"></div>
          <div class="spaceOB"></div>
          <div class="spaceOB"></div>
          <div class="spaceOB"></div>
          <div class="spaceOB"></div>
          <div class="spaceOB"></div>
     </div>
     <div id="spaceHelp">
          Click The front block or try selecting
          a block from the back
     </div>
</div>

If you would like to use or add to this example please do:)

CSS: Position-x and Position-y (Updated)

Updated code

I’ve updated the article and code to use more modern methods. See the CodePen below for more details:

Position-x: Position-y:

View CodePen

Please visit the CodePen above if you would like to implement position-x and position-y.

[Caution] Below is the pre 2009 method if anyone is still interested…

While building out a content management system for DMP I needed to create a toolbar which would stay with position: fixed; on the y-axis, but act like position: absolute on the x-axis. To achieve this I used a clever JavaScript class from David Walsh called scrollspy.

View the old Demo

The JavaScript

Things you will need first: Mootools (This demo uses 1.2.4) and the ScrollSpy plugin from David Walsh. Next write this for you element:

var ss = new ScrollSpy({
     mode: 'horizontal',
     onTick: function(position,state,enters,leaves) {
          $("sidePanel").style.left = -position.x+"px";
     },
     container: window
});

The CSS

In the CSS use position: fixed; because we have handled the position-x: absolute; in JavaScript. so:

#sidePanel {
     position:fixed;
     left:0;
     top:0;
     width:250px;
     z-index:1000;
}

The above example will keep our sidePanel element from disappearing when you scroll down the page but it will scroll with the page when the user scrolls right.

To do the opposite ie. position-x: fixed; position-y: absolute; In the JavaScript change mode: ‘horizontal’ to mode: ‘vertical’ and -position.x+”px”; to -position.y+”px”; and that’s it any comments, ideas or improvements leave them below.

RickyH – Halloween Logo

[UPDATE 02/07/2013]

I found this kicking around since 2009. What was I thinking:
Caution flashing images:
Stars DEMO Click [FUTURE] to freak out.
Follow cursor DEMO

Original article

So its Halloween again and to celebrate I decided to create a new logo. I have to begin by apologizing to people using Internet Explorer because the Logo simply won’t work; this is partially to do with me being too lazy to port it over and partly because IE stinks and doesn’t support the CANVAS element.

The following steps show how i made my Halloween Logo:

Step 1: Turn your logo into a mask

New Design Of RickyH.co.uk

To change a logo into a mask simply select the outline of your logo shape. Photoshop: (cmd/ctrl click layer); and remove the selection from a solid square of slightly bigger size. Set the mask-image’s background-color to the background-color of your website (In my case my #141414). Now save the image with a transparent background as .png (or .gif if you care about IE6). View my image

Step 2: The HTML

<div id="headerimg">
     <canvas id="bloodyMess" />
     <a href="http://www.rickyh.co.uk/"/>
</div>

So we have three elements: The holder div, the canvas element and an anchor element.

Step 3: The CSS

#headerimg {
     position:absolute;
     background-color:#141414;
     width:157px;
     height:188px;
     left:45px;
     top:30px;
}

#bloodyMess {
     position:absolute;
     background-color:#141414;
     width:157px;
     height:188px;
     z-index:1;
     left: 0;
     top: 0;
}

#headerimg a {
     position:absolute;
     background-image:url(images/logoIn.png);
     display:block;
     width:157px;
     height:188px;
     left:0;
     top:0;
     z-index:1001;
}

As you can see from the css, all the elements are positioned absolute. This is to take advantage of using z-index to position the anchor element above the canvas element. The anchor element uses the image-mask we created earlier as the background-image.

Step 3: The JavaScript

This example uses a stripped down version of Christophe Résigné amazing Starfield experiment. I also use Mootools version 1.2.4.

var blood_x_save,blood_y_save;
var drip_speed= 0.01;
var blood_drops = 500;
var star=new Array(blood_drops);
var context;
var bloodtimeout = 0;
var bloodfps= 25;

var Page = {
     initialize: function(){
     initBlood();
     doLogo();
     }
}

window.addEvent("domready", Page.initialize);

function doLogo(){
     $("headerimg").getElement("a").addEvents({
          'mouseover': function(){
               $("bloodyMess").fade(1);
               animBlood();
          },
          'mouseout': function(){
               $("bloodyMess").fade(0);
               clearTimeout(bloodtimeout);
          }
     });
} 

function initBlood()
{
     $("bloodyMess").setStyle("opacity", "0");
     var a=0;
     for(var i=0;i<blood_drops;i++)
     {
          star[i]=new Array(5);
          star[i][0]=Math.random()*157*2-78*2;
          star[i][1]=Math.random()*188*2-89*2;
          star[i][2]=Math.round(Math.random()*172.5);
          star[i][3]=0;
          star[i][4]=0;
     }
     var bloodyMess=$('bloodyMess');
     context=bloodyMess.getContext('2d');
     bloodyMess.width = 157;
     bloodyMess.height = 188;
     context.fillStyle='rgb(149,4,4)';
     context.strokeStyle='rgb(0,0,0)';
}

function animBlood()
{
     context.fillRect(0,0,157,188);
     for(var i=0;i<blood_drops;i++)
     {
          test=true;
          blood_x_save=star[i][3];
          blood_y_save=star[i][4];
          star[i][0]+=11>>4;
          if(star[i][0]>78<<1){
               star[i][0]-=157<<1;
               test=false;
          }
          if(star[i][0]<-78<<1){
               star[i][0]+=157<<1;
               test=false;
          }
          star[i][1]+=31>>4;
          if(star[i][1]>89<<1) {
               star[i][1]-=188<<1;
               test=false;
          }
          if(star[i][1]<-89<<1) {
               star[i][1]+=188<<1;
               test=false;
          }
          star[i][2]-=drip_speed;
          if(star[i][2]>172.5) {
               star[i][2]-=172.5;
               test=false;
          }
          if(star[i][2]<0) {
               star[i][2]+=172.5;
               test=false;
          }
          star[i][3]=78+(star[i][0]/star[i][2])*300;
          star[i][4]=89+(star[i][1]/star[i][2])*300;
if(blood_x_save>0&&blood_x_save<157&&blood_y_save>0&&blood_y_save<188&&test)
          {
               context.fillStyle='rgba(149, 4, 4, 0.5)';
               context.lineWidth=(1-0.005*star[i][2])*5;
               context.beginPath();
               context.moveTo(blood_x_save,blood_y_save);
               context.lineTo(star[i][3],star[i][4]);
               context.stroke();
               context.closePath();
          }
     }
     bloodtimeout=setTimeout('animBlood()',bloodfps);
}

This is the most complicated part. First I fire two functions: initBlood() and doLogo() using Mootools domready event.

initBlood() initializes the CANVAS element and the array to handle the blood. It also sets the CANVAS elements opacity to 0 because I didn’t want to view the blood until you hover over it.

doLogo() handles the hover of the anchor element. On mouseover I fade-in the CANVAS element and begin the blood effects. On mouseout I fade out the CANVAS element and stop the effects using clearTimout(); This saves on the clients CPU when the effects not in use.

initBlood() This is used to handle the blood effects. It should run at 25fps given you’re using a browser with a good JavaScript engine and that your CPU isn’t from before the millennium. The function will loop until the clients mouse leaves the anchor element.

Step 4: View the beast

To view my example simply roll your mouse over my logo. Its positioned in the top-left-hand corner.

RickyH new blog design/concept

I was wanting to do something different and new with blog-design. I’ve created word-press templates before but they all follow the same format: the new design concept incorporates some new technologies such as HTML5 and some clever JavaScript written by myself and the wonderful MooTools community. So what did I do:

Standards

I wanted to experiment with whats new with HTML5 and CSS3 so I started at the top with the new doctype:

<!DOCTYPE html>

Simple isn’t it! This little bute tells the browser to render as HTML5. Next was to make my HTML code valid and forget about the CSS (till it caches up).

Optimization

This is the first time I’ve really concentrated on web optimization and it was somewhat frustrating but highly educational. The first plug was a great tool from the developers from Yahoo called Smush.it. Smush.it is a web-based image optimization tool that reduced my images by up-to 60% in size. I’d used pngcrush before but Smush.it’s great interface makes image optimization extremely simple.

Below are the savings gravatar would make if they Smushed there images 11.28% off their server bandwidth:

smush it rules

Next was gzip and where my frustration began. If your like me and have a small version for web hosting, chances are you wont be able to Gzip files through your Apache .htaccess file. The next of my worries was the lack/poor documentation if you have to gzip without htaccess. Through countless hours of searching i found these miracle slices of code. They do your gzip though PHP.

Firstly try saving your style sheets with style.php file extension and insert this at the top:

<.?php 
   ob_start ("ob_gzhandler");
   header ("content-type: text/css; charset: UTF-8");
   header ("cache-control: must-revalidate");
   $offset = 60 * 60;
   $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";
   header ($expire);
?.> 

And for your java-script files use javascript.php and insert this at the top:

<.?php 
   ob_start ("ob_gzhandler");
   header ("content-type: text/javascript; charset: UTF-8");
   header ("cache-control: must-revalidate");
   $offset = 60 * 60;
   $expire = "expires: " . gmdate ("D, d M Y H:i:s", time() + $offset) . " GMT";
   header ($expire);
?.> 

With all this and more I managed my grade A on Yslow and a perfect score for small site/blog. (on the home page anyway)!

Yslow perfect score

Layout

My idea was to show blog posts by the month they where written. Months would be displayed vertically and posts horizontally. I also wanted to integrate a lazy load feature to load moths of posts ass the user scrolls down the blog. This would save on bandwidth for users just viewing my latest posts.

My next idea was to use categories as ajax filters for posts… For instance if someone only was interested in JavaScript they could click the link which would hide none JavaScript posts and do an Ajax call to gather posts not displayed.

Both these features are not implemented at the time of writing but i cant imagine would take longer than a weekend to implement.

Design

The design criteria was based around saving bandwidth. I only get 2GB download a month from my web hosting so minimization was key. No Flash, small images and externally hosted JavaScript frameworks (thanks google).

Enhancements

Please feel free to add suggestions below. I’m already considering switching the dark design to light for readability. What are your thoughts?