CanJs Livebinding vs. Ember vs. Backbone
Animating 100 (or N) circles
by sporto
HTML
<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="http://cloud.github.com/downloads/bitovi/canjs/can.jquery-1.1.3.min.js"></script>
<script src="http://backbonejs.org/backbone-min.js"></script>
<script src="http://cloud.github.com/downloads/emberjs/ember.js/ember-0.9.4.min.js"></script>
<button onclick="runCan()">Animate with Can</button>
<button onclick="runBackbone()">Animate with Backbone</button>
<button onclick="runEmber()">Animate with Ember</button>
<button onclick="reset()">Reset</button>
<div id="grid"></div>
<script type="text/ejs" id="ejs-template">
<% list(boxes, function( box ) { %>
<div class="box-view">
<div class="box" id="box-<%= box.count %>" style="<%= box.style() %>">
<%= box.content() %>
</div>
</div>
<% }) %>
</script>
<script type="x-template" id="underscore-template">
<div class="box" id="box-<%= number %>" style="top: <%= top %>px; left: <%= left %>px; background: rgb(0,0,<%= color %>);">
<%= content %>
</div>
</script>
<script type="text/x-handlebars" id="handlebars-template" data-template-name="box">
<div class="box" {{bindAttr id="model.number" style="model.style"}}>
{{ model.content }}
</div>
</script>
<script type="text/x-template" id="knockout-template">
<div data-bind="foreach: boxes">
<div class="box-view">
<div class="box" data-bind="style: {top: top(), left: left(), background: color()}, text: content()"></div>
</div>
</div>
</script>
<script type="text/x-yui-handlebars" id="yui-handlebars-template">
<div class="box" id="box-{{number}}" style="top: {{top}}px; left: {{left}}px; background: rgb(0,0,{{color}});">
{{content}}
</div>
</script>
CSS
p {
font: 12px/16px Arial;
margin: 10px 10px 15px;
}
button {
font: bold 14px/14px Arial;
margin-left: 10px;
}
#grid {
margin: 10px;
}
.box-view {
width: 20px; height: 20px;
float: left;
position: relative;
margin: 8px;
}
.box {
border-radius: 100px;
width: 20px; height: 10px;
padding: 5px 0;
color: #fff;
font: 10px/10px Arial;
text-align: center;
position: absolute;
}
JavaScript
// Change N to change the number of drawn circles.
var N = 100;
//CanJS
(function() {
var Box = function() {
return {
count: 0,
top: function() {
return (Math.sin(this.attr('count') / 10) * 10) + 'px'
},
left: function() {
return (Math.cos(this.attr('count') / 10) * 10) + 'px'
},
color: function() {
return 'rgb(0,0,' + (this.attr('count')) % 255 + ')'
},
content: function() {
return this.attr('count') % 100
},
tick: function() {
this.attr('count', (this.count++));
},
style: function() {
this.attr('count');
return 'top: ' + this.top() + '; left: ' + this.left() + '; background: ' + this.color() + ';';
}
}
},
canInit = function() {
boxes = new can.Observe.List();
for (var i = 0; i < N; i++) {
boxes.push(new Box());
}
$('#grid').append(can.view('ejs-template', {
boxes: boxes
}));
},
canAnimate = function() {
for (var i = 0; i < N; i++) {
boxes[i].tick();
}
window.timeout = _.defer(canAnimate);
};
window.runCan = function() {
reset();
canInit();
canAnimate();
};
})();
// The Backbone implementation:
(function() {
var Box = Backbone.Model.extend({
defaults: {
top: 0,
left: 0,
color: 0,
content: 0
},
initialize: function() {
this.count = 0;
},
tick: function() {
var count = this.count += 1;
this.set({
top: Math.sin(count / 10) * 10,
left: Math.cos(count / 10) * 10,
color: (count) % 255,
...