Archive for the ‘Uncategorized’ Category

Site redesign

Monday, February 20th, 2012

So I decided to redesign my blog and add my portfolio to superted.me (it used to be at tedlittledale.co.uk) as I now use Superted Ltd as my trading name.
I’ve been using this great full screen color picker, http://color.aurlien.net/, for a while now whenever I’ve needed a bit of inspiration to pick a color for something. I really like the mouse effect they use and so used that as the inspiration for the redesign. I also really like Futura so wanted to use some nice big text.

Twitter widget

Thursday, June 2nd, 2011

I’ve finally had some downtime recently so I’ve been spending time redesigning my portfolio site. I wanted to add a twitter widget that animated between recent tweets using a bit of css3 transition magic. This is what I came up with (I’ve sped up the interval time for the demo):

In terms of markup, the tweets are generated as a simple unordered list using php.

The javascript was pretty simple really. First some empty divs are added to the containing div to act as a mask. These are sized and positioned so that they cover the whole tweet when the ‘right’ css property of each div is set to 0. They are also given an incremental transition delay so that the top div animates first and the rest follow.

When the tweet transitions the ‘right’ property is set to 0 hideing the tweet. The current tweet is then swapped for the next before the ‘right’ property is set again to the width of the tweet, thus revealing the next tweet. The animation is handled by the css.

The JS

/**
	 * Add markup to twitter div for animation
	 * @private
	 * @param {jQueryObject} section The parent element
	 * @returns Describe what it returns
	 * @type String|Object|Array|Boolean|Number
	 */
	var initTwitterAnimation = function(section){
		var current = section.find('li:visible'), top = 0;
		current.parent().wrap('<div class="shutterWrap"></div>');
		var wrap = 	section.find('.shutterWrap'),
					shutterHeight = Math.ceil(current.outerHeight()/10),
					shutterWidth = current.outerWidth();
		for(var i = 0; i < 10; i++){
			wrap.css('position','relative').append('<div class="shutter"></div>');
		}
		section.find('.shutter').each(function(i){
			$(this).css({
				height : shutterHeight+'px',
				position : 'absolute',
				top : top + 'px',
				width : '100%',
				background : '#fff',
				right:-shutterWidth+'px'
			});
			this.style.webkitTransitionDelay = i*(0.05)+'s';
			this.style.MozTransitionDelay = i*(0.05)+'s';
			top += shutterHeight;
		});
		setTimeout(function() {
			animateTwitter(section, shutterWidth);
		}, 1000);
	};//initTwitterAnimation

	var animateTwitter = function(section, shutterWidth){
		var hiding = true;
		var current = section.find('li:visible'), top = 0, next;
		var next = current.next();
		if(next.length === 0){
			next = section.find('li:first');
		}
		var goToNext = function(){
			if(hiding){
				current.hide();
				next.show();
				shutterHeight = Math.ceil(next.outerHeight()/10);
				section.find('.shutter').each(function(i){
					$(this).css({
						height : shutterHeight+'px',
						top : top + 'px'
					});
					top += shutterHeight;
				});
				section.find('.shutter').each(function(){
					$(this).css({
						right : -shutterWidth+'px'
					});
				});
				hiding = false;
			}
		}
		section.find('.shutter:last')[0].addEventListener('webkitTransitionEnd', goToNext, true);
		section.find('.shutter:last')[0].addEventListener('transitionend', goToNext, true);
		section.find('.shutter').each(function(){
			$(this).css({
				right:0+'px'
			});
		});
		setTimeout(function() {
			animateTwitter(section, shutterWidth);
		}, 2000);
	};//animateTwitter

The CSS

/* twitter */
.twitter{/*container*/
	width:240px;
	padding: 10px;
	float: left;
	overflow: hidden;
}
.twitter li{/*each tweet is an li*/
	list-style: none;
	display: none;
	background-color: #3 3ccff;
	background-image:-webkit-gradient(radial, 50% 50%, 1, 50% 50%, 170, from(#33ccff), to(rgba(51,204,255,0.4)));
	background-image:-moz-radial-gradient(50% 50% 90deg,ellipse closest-side, #33ccff, rgba(51,204,255,0.5));
	color: #fff;
	padding: 10px;
	-webkit-border-radius: 10px;
	   -moz-border-radius: 10px;
	        border-radius: 10px;
	font-size: 18px;
}
.twitter li:first-child{/*show the first tweet by default*/
	display: block;
}
.shutter{/*add the transition to the shutter divs*/
	-webkit-transition: right 0.2s ease-in;
	-moz-transition: right 0.2s ease-in;
}

iAd ‘SDK’

Tuesday, June 29th, 2010

When Apple first announced their iAd platform they mentioned that they would be releasing an SDK to allow developers to build these ads. This was intriguing as I don’t know any developers who would use an SDK to create HTML/Javascript applications, as opposed to using a text editor such as Textmate. I was a bit concerned that Apple would restrict iAd development to some sort of WYSIWYG built into the XCode application.

So anyway, when Apple officially announced iPhone 4 they released iAd JS, which was available for download as a dmg from the iPhone developer center (paid developer login required I think).

You have to install this using the mac installer but is essentially just unzips a directory into the root developer folder:

The iAdTester.app is an iphone app that you install via itunes and allows you to test your iAds on an iPhone.

The tests folder container examples of all the widgets, controls etc that can Apple has provided for used within iAds. E.g. CarouselView is the the 3D carousel which they used for the toy-story iAd which I recreated (I haven’t dug into their code so see how they’ve implemented it yet). Most of the examples show how to create controls that look and behave like native iPhone controls.

So as you can see this isn’t really an SDK but a javascript library to help in the process of creating iAds. I think this is a good approach as it allows developers to create interfaces with familiar controls but also gives them freedom to use their imagination to create anything that html5/css3 allows.

I’ll save the deployment and testing process for another post but it is fairly simple and painless

Shattering Images

Tuesday, April 27th, 2010

I’ve been messing around with css3 transitions and seeing how many can run simultaneously without noticeable performance lag. So, inspired by this cool bit of canvas wizardry I thought I’d create some image shattering effects to test how well css transitions could cope.

Below are two videos of the results. The first is doing simultaneously animating 25 elements in 3d and cope fine without any lag at all. The second is animating 256 elements and although there is some lag after clicking the image, the animation itself is remarkably smooth. You can view the first for yourself at http://superted.me/stuff/shatter.html on any webkit browser although the 3d effect only works on the iphone.

There were three key steps in creating this effect. The first was a function to create the image, which is essentially a collection of divs with the same background image positioned to look like a single image:

shatter.createMozaic = function(uid, first){
		var w = 320 / PANELS;
		var h = w;
		for(var i = 0, l = PANELS; i < l; i++){
			for(var j = 0; j < PANELS; j++){
				//create a div for each panel
				var div = document.createElement('div');
				div.className = 'imgSection '+uid;
				//offset each panel
				div.style.top = (j * h) + 50 + 'px';
				div.style.left = (i * w) + 'px';
				div.style.width = w + 'px';
				div.style.height = h  + 'px';
				//offset the background relative to the position of the div
				div.style.backgroundPosition = (-i * w) +'px '+(-j * h )+'px';
				var matrix = new WebKitCSSMatrix();
				//if it is the first image
				if(first){
					//no image rotation and full opacity
					div.style.webkitTransform	= matrix.rotate(0, 0, 0);
					div.style.opacity = 1;
				}
				else{
					//random X and Y rotation and a Z translation
					var newX = Math.random() * 360;
					var newY = Math.random() * 360;
					div.style.webkitTransform	= matrix.rotate(newX, newY, 0).translate(0, 0, 380);
				}
				document.body.appendChild(div);

			}
		}

	};

The second function was to break up the image by changing the rotation and translation of each div:

	shatter.shatter = function(uid){
		var sections = document.getElementsByClassName(uid);
		//loop through each panel of this image
		for(var i = 0, l = sections.length; i < l; i++){
			var theTransform = window.getComputedStyle(sections[i]).webkitTransform;
			var matrix = new WebKitCSSMatrix(theTransform);
			var newX = Math.random() * 360;
			var newY = Math.random() * 360;
			//give each panel a random X and Y rotation and set opacity to 0
			sections[i].style.webkitTransform	= matrix.rotate(newX, newY, 0).translate(0, 0, 380);
			sections[i].style.opacity = 0;
		}
	};

And finally a function to reassemble an image:

	shatter.unShatter = function(uid){
		var sections = document.getElementsByClassName(uid);
		//loop through each panel of this image
		for(var i = 0, l = sections.length; i < l; i++){
			var matrix = new WebKitCSSMatrix();
			sections[i].style.webkitTransform	= matrix.rotate(0, 0, 0).translate(0, 0, 0);
			sections[i].style.opacity = 1;
		}

	};

And of course some css was needed to handle the transitions

.imgSection {
	position: absolute;
	-webkit-transition-property: -webkit-transform, left, opacity;
	-webkit-transition-duration: 1000ms, 1000ms, 1000ms;
	-webkit-transition-timing-function : ease-out, ease-out, linear;
	-webkit-transition-delay: 0, 500ms, 0;
	-webkit-backface-visibility: hidden;
	-webkit-transform-style: preserve-3d;
	opacity:0;
}
.img1{
	background: url(../img/cb1.jpg) no-repeat 0 0;
}

Touch event tool

Tuesday, April 27th, 2010

I just though I’d share a little tool I built to help me understand touch events on the iPhone. If you are using a touch enabled webkit browser you can see the tool in action using the following link http://bit.ly/touchEvent. I’ve only tested this on an iPhone but I’d be interested to hear if it works on android and webOS phones.

And here’s the code.

var template = '<ul>'+
					'<li>identifier:{identifier}</li>'+
					'<li>screenX:{screenX}</li>'+
					'<li>screenY:{screenY}</li>'+
					'<li>clientX:{clientX}</li>'+
					'<li>clientY:{clientY}</li>'+
				'</ul>';
var FIRST_FINGER = 0, SECOND_FINGER = 1
document.addEventListener('touchstart', function(e) {
	e.preventDefault();
	//identify as the first finger
	jTouchTest.currentFingers[e.touches[0].identifier] = FIRST_FINGER;
	//use supplant function to print out the properties of the e.touches object for the first finger
	document.getElementById('touchStart')
			.getElementsByClassName('touch')[0]
			.getElementsByTagName('div')[0]
			.innerHTML = supplant(template, e.touches[0]);
	//if there is a secondary touch
	if(e.touches[1]){
		//identify as the second finger
		jTouchTest.currentFingers[e.touches[1].identifier] = SECOND_FINGER;
		//use supplant function to print out the properties of the e.touches object for the first second
		document.getElementById('touchStart')
				.getElementsByClassName('touch')[1]
				.getElementsByTagName('div')[0]
				.innerHTML = supplant(template, e.touches[1]);
	}

}, false);
document.addEventListener('touchmove', function(e) {
	e.preventDefault();
	//which finger is it
	var finger = jTouchTest.currentFingers[e.changedTouches[0].identifier];
	//use supplant function to print out the properties of the e.changedTouches object for the finger that is moving
	document.getElementById('touchMove')
			.getElementsByClassName('touch')[finger]
			.getElementsByTagName('div')[0]
			.innerHTML = supplant(template, e.changedTouches[0]);
	//if there is a second touch
	if(e.changedTouches[1]){
		finger = jTouchTest.currentFingers[e.changedTouches[1].identifier];
		document.getElementById('touchMove')
				.getElementsByClassName('touch')[finger]
				.getElementsByTagName('div')[0]
				.innerHTML = supplant(template, e.changedTouches[1]);
	}

}, false);
document.addEventListener('touchend', function(e) {
	e.preventDefault();
	//if this event matches one the current touches
	if(jTouchTest.currentFingers[e.changedTouches[0].identifier] !== undefined){
		//which finger is it
		var finger = jTouchTest.currentFingers[e.changedTouches[0].identifier];
		//use supplant function to print out the properties of the e.changedTouches object for the finger that has left the screen
		document.getElementById('touchEnd')
				.getElementsByClassName('touch')[finger]
				.getElementsByTagName('div')[0]
				.innerHTML = supplant(template, e.changedTouches[0]);
	}

}, false);

Toy Story iAd Navigation

Monday, April 19th, 2010

So I’m sure many of you will have seen Steve Jobs show off the new iAd platform and if you’re a developer like myself you were probably interested to see that the iAd platform is HTML5 based. As part of the Toy Story 3 iAd there was a nice 3d carousel for the video navigation as shown below.

Anyway, Jobsie reckoned that making something like this in HTML5 was ‘real easy’ so I thought I’d see if he was right. If you’ve got an iphone head over to bit.ly/iAdEasy for the full ‘emotional’ experience of the results, or you can see a screencast below.

I used pictures of my brother’s dog, Chopper, instead of pixar characters as his images aren’t copywrited and he doesn’t have lawyers!

So was it real easy? Well it wasn’t real easy but that was partly as there isn’t a huge amount of documentation or tutorials out there.

[Update] To clarify this point, all CSS3 transitions/animations are fully documented on the Webkit and Apple websites, it’s just that it takes a bit of digging to find exactly what you are looking for and there aren’t many tutorials which show features like WebKitCSSMatrix in action.

I used the webkit team’s morphing cube example as my starting point as that showed how to get a bunch of flat elements arranged as a 3d ring. I just created a function to add the 3d transform to each li dynamically rather than in the css file:

jAd.createRing = function(){
		var items = shape.getElementsByTagName('li');
		var angle = 360 / items.length, newAngle;
		for(var i = 0, l = items.length; i < l; i++){
			newAngle = (angle * i);
			var matrix = new WebKitCSSMatrix();
			items[i].style.webkitTransform	= matrix.rotate(newAngle, 0, 0).translate(0, 0, 380);
		}
	}

The next step was to bind the finger swiping events. Webkit allows you to bind ‘touchstart’, ‘touchmove’ and ‘touchend’ events to any html element and from the touch event you can access the screenPosition and the time of the touch. Using these it is easy to determine which direction the swipe is and how hard the user swiped

jAd.bindTouches = function(){
//ignore the touchmove event
		document.addEventListener('touchmove', function(e) {e.preventDefault();});
		document.addEventListener('touchstart', function(e) {
			e.preventDefault();
//e.touches is an array (for multitouch usage) but we just want the first finger down
			var touch = e.touches[0];
//save the time and the screenY coordinate
			jAd.currentTouch.startY = touch.screenY;
			jAd.currentTouch.startTime = e.timeStamp;
		}, false);
		document.addEventListener('touchend', function(e) {
			e.preventDefault();
			var touch = e.changedTouches[0];
			jAd.currentTouch.endY = touch.screenY;
 //work out the speed using the saved coordinate and time
			var time = e.timeStamp - jAd.currentTouch.startTime;
			var speed = (jAd.currentTouch.startY - jAd.currentTouch.endY)/time;
 //send the speed to the spin function
			jAd.spin(speed);

		}, false);
	};

The speed that is sent to the spin function can be positive or negative and this determines which way the nav spins.

Next I had to create a function to change the rotation of the <ul> element which contains the <li> elements that make up the ring.

jAd.spin = function(speed){
 //get a string representation of the current 3dCSSMatrix of the <ul> (jAd.shape)
		var theTransform = window.getComputedStyle(jAd.shape).webkitTransform;
 //from this create a new WebKitCSSMatrix
		var matrix = new WebKitCSSMatrix(theTransform);
 //do some stuff to get a number that is somewhere between 0 and 179
		var newX = Math.round(speed * 120);
		newX = (newX > 179) ? 179 : ((newX < -179) ? -179 : newX);
//rotate the <ul> in the x plane by this value
		shape.style.webkitTransform	= matrix.rotate(newX, 0, 0);
	};

Note that this function doesn’t animate the ring, it simply changes the rotateX value of the webkit-transform css property. In order to get the animation to happen we have to give the <ul> some webkit-transition css.

#shape {
/* this tell it to animate whenever the -webkit-trasform property changes */
	-webkit-transition-property: -webkit-transform;
	-webkit-transition-duration: 1500ms;
	-webkit-transition-timing-function : ease-out;
	-webkit-transition-delay: 0;
}

And that’s pretty much it, feel free to dig around in the source code and do some experimenting. I haven’t added any interaction to the contents of the carousel yet, I’ll be doing that soon and writing another post.

This is my first time I’ve written a how-to so sorry if I glossed over anything. Feel free to post questions in the comments and I’ll do my best to answer them

Welcome to superted.me

Monday, April 19th, 2010

Hi, thanks for visiting my blog, here’s a bit about me.

My name is Ted. I’m not that super. However I did enjoy watching Superted as a kid and thought it would make a good blog title so there you go.

I’m a web interface developer by trade so that is what I’ll be blogging about mostly. I’m really interested in innovative user interfaces and data visualisation using the latest funky HTML5 and CSS3 techniques so I plan to talk about that a fair bit as well as other stuff which catches my eye.

You can find out more about me and my contact details at my portfolio site tedlittledale.co.uk. I also thought I’d better be a tweeter if I’m going to try to be a blogger so I’d love for you to follow me and boost my numbers (I currently have 3 followers).