When I first began digging into javascript-based graphics, I was confused about the difference between HTML5 Canvas and SVG. To my naive eyes, both technologies seemed like magical factories full of pixel elves, just hammering away at whatever visions might wisp across my fickle mind: animated puppies, stomping unicorns, tea-drinking loch-ness monsters and so on. Visually-based design environments like Adobe Photoshop and Illustrator often encourage us to learn how to work with a tool before, if ever, understanding it’s philosophy. Regardless of the intended purpose of the technology, we can generally make it work by pushing pixels about until something clicks. The case with web is very different. It is critical to understand a technology’s purpose in order to easily interface with it’s pixel elves.
Canvas and SVG are great examples, because they are about as metaphysically different as possible for something as boring as code-based graphics interfaces. Because of this, it is important to understand how they are unique before choosing one to work with.
If all of your visual elements are a class of chipper 5th graders, then SVG is the art teacher. It is humanistic in philosophy and treats each and every shape as a unique mathematical object. It stores it’s graphical information as vector shapes based in XML— meaning it may be a hand written document or dynamically generated. I find that SVG is much easier for designers to understand because they are accustomed to seeing visual elements as unique objects.
Canvas is most easily thought of as a scriptable image, and is designed to be monogamous with Javascript. It is great for any application where speed and pixel-manipulation are important. Philosophically, canvas can have a more surface level relationship with graphics. Like a fifth grade gym teacher, it will not specifically remember any one object, but dumbly render whatever you tell it to, before abruptly forgetting everything. If you want anything to be remembered, you need to remember it yourself using Javascript. If you want to change something, you must re-render the entire image.
How it works
The reason I bring all of this up, is because Cluster utilizes both canvas and SVG for their unique capabilities. It uses canvas to quickly rendered a chunk of typography and store all of the pixel information in an array using the awesome getImageData function. It then leverages that information to create SVG circles on a grid. This makes interaction much more practical because SVG, like our art teacher, remembers every element and can bind events to them in SVG’s document object model. If we were to use canvas all the way through, we would need to detect the position of the mouse and guess which object was being hovered over, since our meat-headed gym teacher can’t even remember our names.
Using Cluster
If you want to call Cluster, you need to design the type beforehand, and then point cluster at the element. To do this, simply write:
cluster.init('element-to-cluster')
This wont hide the text, so you will need to do that too, using the text-indent property or some independent opacity color rule like RGBA or HSLA.
#element-to-cluster {
text-indent: -9999px
}
There are a few options in Cluster. Call them before you call the function.
cluster.density = 8 // frequency of circles
cluster.radius = 3 // the radius of the circles
cluster.speed = 1000 // the speed of the fade in
cluster.colors = ["#00B6B8","#ED5F4C","#F9A235","#2E3192"]
cluster.timeout = -700 //wait before animation timeout
cluster.init(element-to-cluster)
Using it with web fonts
Like all of the scripts on this site, I highly recommend you nest the function inside of a Javascript callback. Here I use typekit, so my callback looks something like this:
try {
Typekit.load({
active : function() {
$(document).ready(function(){
cluster.init('element-to-cluster')
})
},
inactive: function() {
//do something else
}
})
} catch(e){}
I try to limit the amount of designing that happens in the code, so you may need to do some nudging around using css. I recommend using something like web inspector or firebug to sniff around the created elements and style it from there.
Animating with SVG and pure JS
Cluster runs on pure SVG and Javascript. I’ve generally found scripting with SMIL animations to be frustrating, so animations here happen the good old fashioned way: with an animation loop. This turned out to be much prettier and cleaner. I’m sure that SMIL is faster on many devices, so you may need to weigh this out on a project-to-project basis. My loop looks a little like this, though I would recommend opening the code if you are really interested:
t.grow = function(parent,evt) {
evt.target.Y = 0
var r = parent.radius, that = this
this.loop = function() {
parent.root.suspendRedraw(10000)
evt.target.Y = evt.target.Y - 6
evt.target.setAttribute('transform',
'translate(' + 0 + ',' + evt.target.Y + ')')
r = r + 0.1
evt.target.setAttribute('r',r)
parent.root.unsuspendRedrawAll()
if(evt.target.Y < parent.timeout) {
clearInterval(that.timer)
}
}
that.timer = window.setInterval(this.loop,30)
}
this.el.addEventListener("mouseover",
function(event){
t.grow(parent,event)
},
true)