Aug 30

Via Phil Franks comes an interesting HTML5/CSS3 site for There Studio, which is a kind of coworking space in London:

The site itself has a number of circles with information bouncing on the screen that respond to mouse clicks and moves.

Let’s crack the site open using View Source and see how they are doing things. First, they have a repeated background with a little plus symbol with the following style rule on the <body> tag:

CSS:

background: #ddd url(‘../images/bg.gif’) 50% 0 repeat fixed;
 

The textual content in each of the circles is clean semantic HTML that is search engine friendly:

HTML:

<div class=“section who first”>
  <h3>Who</h3>
  <p>Creatives, makers, thinkers <span class=“ampersand”>&amp;</span> doers</p>
</div>

To turn that into this:

The <h3> is first transformed into having an underline with the padding and margin being on the bottom:

CSS:

h3 {
        border-bottom: 1px solid #ccc;
        display: block;
        font-size: 25px;
        font-weight: normal;
        padding: 0 0 10px;
        margin: 0 0 8px;
}
 

JavaScript creates the circle. The script tags themselves are at the end of the HTML page at the bottom of the <body> tag, a good performance practice in general.

The heart of drawing each circle is in the createBall and createContentBall methods. If a ball will have HTML content, then the createContentBall method is used, otherwise the createBall method is used. Let’s look at the createContentBall method; we’ll break it down:

JAVASCRIPT:

function createContentBall(className,size,color,html) {
  var element = document.createElement( ‘div’ );
  element.className = className;
  element.width = element.height = size;
  element.style.position = ‘absolute’;
  element.style.left = -size + ‘px’;
  element.style.top = -size + ‘px’;
  element.style.cursor = “default”;
  canvas.appendChild(element);
  elements.push( element );
  var circle = document.createElement( ‘canvas’ );
  circle.width = size;
  circle.height = size;
  if (className !==‘image’ && className !==‘image first’) {
    var graphics = circle.getContext( ’2d’ );
    graphics.fillStyle = color;
    graphics.beginPath();
    graphics.arc( size * .5, size * .5, size * .5, 0, PI2, true );
    graphics.closePath();
    graphics.fill();
  }
  element.appendChild( circle );
  content = document.createElement( ‘div’ );
  content.className = “content”;
  content.onSelectStart = null;
  content.innerHTML = html;
  element.appendChild(content);
  if (className !==‘image’ && className !==‘image first’ ) {
    content.style.width = (size – contentPadding*2) + ‘px’;
    content.style.left = (((size – content.clientWidth) / 2)) +‘px’;
    content.style.top = ((size – content.clientHeight) / 2) +‘px’;
  }
  var b2body = new b2BodyDef();
  var circle = new b2CircleDef();
  circle.radius = size / 2;
  circle.density = ballDensity;
  circle.friction = ballFriction;
  circle.restitution = ballRestitution;
  b2body.AddShape(circle);
  b2body.userData = {element: element};
  b2body.position.Set( Math.random() * stage[2], Math.random() * (stage[3]-size) + size/2);
  b2body.linearVelocity.Set( Math.random() * 200, Math.random() * 200 );
  bodies.push( world.CreateBody(b2body) );
}
 

First, we create an absolutely positioned DIV that will house our Canvas tag:

JAVASCRIPT:

var element = document.createElement( ‘div’ );
element.className = className;
element.width = element.height = size;
element.style.position = ‘absolute’;
element.style.left = -size + ‘px’;
element.style.top = -size + ‘px’;
element.style.cursor = “default”;
canvas.appendChild(element);
elements.push( element );
 

Then we draw the actual circle itself using the Canvas tag and append it to our container DIV (Note that an SVG circle created programmatically could have also been used here):

JAVASCRIPT:

var circle = document.createElement( ‘canvas’ );
circle.width = size;
circle.height = size;
if (className !==‘image’ && className !==‘image first’) {
   var graphics = circle.getContext( ’2d’ );
   graphics.fillStyle = color;
   graphics.beginPath();
   graphics.arc( size * .5, size * .5, size * .5, 0, PI2, true );
   graphics.closePath();
   graphics.fill();
}
element.appendChild( circle );
 

Then we create another DIV to house the HTML content itself:

JAVASCRIPT:

content = document.createElement( ‘div’ );
content.className = “content”;
content.onSelectStart = null;
content.innerHTML = html;
element.appendChild(content);
if (className !==‘image’ && className !==‘image first’ ) {
   content.style.width = (size – contentPadding*2) + ‘px’;
   content.style.left = (((size – content.clientWidth) / 2)) +‘px’;
   content.style.top = ((size – content.clientHeight) / 2) +‘px’;
}
 

Notice that we are setting content.onSelectStart to null above; this is so that when you run the mouse button over the text it doesn’t select (An alternative way to do this is to use the HTML pointer-events CSS property).

Next comes code to deal with the physics of the circles, which uses Box2D.js, a JavaScript physics engine ported from Flash:

JAVASCRIPT:

var b2body = new b2BodyDef();
var circle = new b2CircleDef();
circle.radius = size / 2;
circle.density = ballDensity;
circle.friction = ballFriction;
circle.restitution = ballRestitution;
b2body.AddShape(circle);
b2body.userData = {element: element};
b2body.position.Set( Math.random() * stage[2], Math.random() * (stage[3]-size) + size/2);
b2body.linearVelocity.Set( Math.random() * 200, Math.random() * 200 );
bodies.push( world.CreateBody(b2body) );
 

Basically, we define a circle, give it a radius, density, friction, and restitution, and then add it to our collection of shapes with a position and linear velocity. Box2D will then handle the physics and we can just take the values back out to draw things on the screen with a setInterval, which happens in the loop method:

JAVASCRIPT:

function loop() {
  delta[0] += (0 – delta[0]) * .5;
  delta[1] += (0 – delta[1]) * .5;
  world.m_gravity.x = 0 // -(0 + delta[0]);
  world.m_gravity.y = -(100 + delta[1]);
  mouseDrag();
  world.Step(timeStep, iterations);
  for (i = 0; i <bodies.length; i++) {
    var body = bodies[i];
    var element = elements[i];
    element.style.left = (body.m_position0.x(element.width>> 1)) + ‘px’;
    element.style.top = (body.m_position0.y(element.height>> 1)) + ‘px’;
    if (ballRotation && element.tagName == ‘DIV’) {
      var rotationStyle = ‘rotate(‘ + (body.m_rotation0 * 57.2957795) + ‘deg)’;
      element.style.WebkitTransform = rotationStyle;
      element.style.MozTransform = rotationStyle;
      element.style.OTransform = rotationStyle;
    }
  }
}
 

This method gets called with a setInterval periodically. Basically, we apply a delta and a gravity at each time step; see if the mouse is being pressed down (with hooks for touch devices like the iPhone to see if a finger is being pressed down); tell the Box2D World about our gravity and delta and to make an iteration step; and finally use the computed physics values from Box2D to apply CSS3 rotation transforms on our parent DIV and move the element’s CSS top and left values around the screen.

Continue reading »

Tagged with:
May 07

I think we are seeing a new meme. Matt Nowack has taken the awesome HTML5 presentation app in HTML5, which is open source, and has created a presentation discussing jQuery 1.4.

It is good stuff, using the fact that you can embed the features that you want to show. Just as long as you can hit the right arrow to get through the “look at all the people who use jQuery” part (we get it! lots of people use jQuery!)

Salvador Diaz has taken things in another direction. He has ported the HTML5 app to GWT under the hood.

Maybe this presentation app can be the “Java Pet Store” of Ajax libraries :)

Continue reading »

Tagged with:
Apr 13

There was a big cheer at last years Google I/O when Google Wave was demoed. It made a great demo and really showed that the Web can do a looooot more than we think.

It sounds like we will have another big cheer moment for this years Google I/O though, and it will won’t be for a demo, but for something more meaningful.

It appears that Google will open source VP8, the On2 codec at the event. Video has been painful for the Open Web crew. Many bash Theora on the grounds of quality, and then others hit back saying that it is hog-wash. H.264 has been taken up almost ubiquitously, with Mozilla holding out on religious grounds (which has created a groundswell around that decision too). The folks who make money on H.264 extended our puff on the pipe, but wouldn’t it be nice for the Open Web to have a true open video alternative?

That is what folks like the FSF begged Google for when the On2 acquisition was happening. Now we may have our wish.

This doesn’t mean that all is well. Having a codec is one thing, but getting it out there and implemented is another. Chrome and Mozilla may support it out of the gate, but what about Apple and Microsoft? At the very least though, having a truly viable open codec allows us to hold the H.264 folks feet to the fire.

Google also recently funded open video work on ARM that does use Theora. I am looking forward to IO!

Continue reading »

Tagged with:
preload preload preload