Dance.js is dancing based on data. It's much like Backbone.js, but with a foundation for building interactive visualizations in the spirit of D3.js. It comes with Data.js, a uniform interface for handling your domain data.
| window.countries_data = { | |
| "type": { | |
| "_id": "/type/country", | |
| "name": "Countries", | |
| "properties": { | |
| "name": {"name": "Country Name", "type": "string" }, | |
| "languages": {"name": "Languages spoken", "type": "string" }, | |
| "population": { "name": "Population", "type": "number" }, | |
| "gdp": { "name": "GDP per capita", "type": "number" } | |
| }, | |
| "indexes": { | |
| "by_name": ["name"] | |
| } | |
| }, | |
| "objects": [ | |
| { | |
| "_id": "at", | |
| "name": "Austria", | |
| "languages": ["German", "Austrian"], | |
| "population": 8.3, | |
| "gdp": 41.805 | |
| }, | |
| { | |
| "_id": "de", | |
| "name": "Germany", | |
| "languages": ["German"], | |
| "population": 82, | |
| "gdp": 46.860 | |
| }, | |
| { | |
| "_id": "us", | |
| "name": "United States of America", | |
| "languages": ["German", "English", "Spanish", "Chinese", "French"], | |
| "population": 311, | |
| "gdp": 36.081 | |
| }, | |
| { | |
| "_id": "uk", | |
| "name": "United Kingdom", | |
| "languages": ["English", "Irish", "Scottish Gaelic"], | |
| "population": 62.3, | |
| "gdp": 36.081 | |
| }, | |
| { | |
| "_id": "es", | |
| "name": "Spain", | |
| "languages": ["Spanish"], | |
| "population": 30.6, | |
| "gdp": 36.081 | |
| }, | |
| { | |
| "_id": "gr", | |
| "name": "Greece", | |
| "languages": ["Greek"], | |
| "population": 11.0, | |
| "gdp": 36.081 | |
| }, | |
| { | |
| "_id": "ca", | |
| "name": "Canada", | |
| "languages": ["English", "French", "Spanish"], | |
| "population": 40.1, | |
| "gdp": 40.457 | |
| } | |
| ] | |
| }; |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset='UTF-8'/> | |
| <title>Dance.js - The Scatterplot Dance</title> | |
| <link rel='stylesheet' href='scatterplot.css'> | |
| <script src='https://raw.github.com/documentcloud/underscore/87cac5bd057ceafd6f779b1df33de61ca21b5e1d/underscore.js'></script> | |
| <script src='https://raw.github.com/michael/data/fe65cb9ab32fbee59f14f44e17e186cf69ff16a7/data.js'></script> | |
| <script src='http://code.jquery.com/jquery-1.7.2.min.js'></script> | |
| <script src='https://raw.github.com/michael/dance/96cb9a6384acce19202275c6dce9b7fbdac87763/dance.js'></script> | |
| <!-- Countries data --> | |
| <script src='countries.js'></script> | |
| <!-- Dance Performers --> | |
| <script src="scatterplot.js"></script> | |
| <script> | |
| $(function() { | |
| window.countries = new Data.Collection(countries_data); | |
| window.scatterplot = new Scatterplot({}); | |
| scatterplot.update(countries, ["gdp", "population"]); | |
| // Update | |
| function update() { | |
| var language = $('#language').val(); | |
| var query = {}; | |
| if (language) query["languages"] = [ language ]; | |
| var items = countries.find(query); | |
| scatterplot.update(items, [$('#property_x').val(), $('#property_y').val()]); | |
| } | |
| $('#property_x').change(update); | |
| $('#property_y').change(update); | |
| $('#language').change(update); | |
| }); | |
| </script> | |
| </head> | |
| <body> | |
| <div id='container'> | |
| X | |
| <select id="property_x"> | |
| <option value="gdp">GDP (thousands)</option> | |
| <option value="population">Population (millions)</option> | |
| </select> | |
| Y | |
| <select id="property_y"> | |
| <option value="gdp">GDP (thousands)</option> | |
| <option selected="selected" value="population">Population (millions)</option> | |
| </select> | |
| <select id="language"> | |
| <option value="">All</option> | |
| <option value="English">English</option> | |
| <option value="French">French</option> | |
| <option value="German">German</option> | |
| <option value="Greek">Greek</option> | |
| <option value="Spanish">Spanish</option> | |
| <option value="Scottish Gaelic">Scottish Gaelic</option> | |
| </select> | |
| <div id='canvas'></div> | |
| </div> | |
| </body> | |
| </html> |
| body { | |
| font: 15px 'Helvetica Neue' Arial | |
| } | |
| #canvas { | |
| margin-top: 20px; | |
| border: 30px solid #eee; | |
| width: 550px; | |
| height: 350px; | |
| background: #eee; | |
| position: relative; | |
| } | |
| .dot { | |
| -moz-transition-duration: 0.8s; | |
| -webkit-transition-duration: 0.8s; | |
| transition-duration: 0.8s; | |
| position: absolute; | |
| bottom: 0px; | |
| background: steelblue; | |
| opacity: 0.7; | |
| border-radius: 5px; | |
| } | |
| .bar:hover { opacity: 1.0; } | |
| .dot .label { | |
| display: none; | |
| text-transform: uppercase; | |
| position: absolute; | |
| bottom: -25px; | |
| left: 10px; | |
| right: 0; | |
| width: 40px; | |
| text-align: center; | |
| background: #ccc; | |
| padding: 10px; | |
| } | |
| .dot:hover .label { | |
| display: block; | |
| } | |
| .dot .value { | |
| font-weight: bold; | |
| text-transform: uppercase; | |
| position: absolute; | |
| top: -25px; | |
| left: 0; | |
| right: 0; | |
| text-align: center; | |
| } |
| (function(exports) { | |
| // Helpers | |
| // ------------ | |
| function htmlId(obj) { | |
| return obj._id.split('/').join('_'); | |
| } | |
| // Collections you wanna dance with | |
| // ------------ | |
| var collections = { | |
| "items": { | |
| enter: function(items) { | |
| items.each(function(item) { | |
| var dot = $('<div class="dot" id="'+htmlId(item)+'"><div class="label">'+item._id+'</div></div>') | |
| .css('left', Math.random()*$('#canvas').width()) | |
| .css('bottom', Math.random()*$('#canvas').height()) | |
| .css('width', 1) | |
| .css('height', 1); | |
| $('#canvas').append(dot); | |
| }); | |
| // Delegate to update (motion tweening fun) | |
| _.delay(this.collections["items"].update, 200, items); | |
| }, | |
| update: function(items) { | |
| items.each(function(item) { | |
| var cell = $('#'+htmlId(item)) | |
| .css('left', item.pos.x) | |
| .css('bottom', item.pos.y) | |
| .css('width', 10) | |
| .css('height', 10); | |
| }); | |
| }, | |
| exit: function(items) { | |
| items.each(function(i) { $('#'+htmlId(i)).remove() }); | |
| } | |
| } | |
| }; | |
| // Scatterplot Visualization | |
| // ------------ | |
| var Scatterplot = Dance.Performer.extend({ | |
| collections: collections, | |
| initialize: function(options) { | |
| this.data["items"] = options.items; | |
| }, | |
| layout: function(properties) { | |
| var that = this; | |
| // Prepare scales | |
| function aggregate(p, fn) { | |
| var values = _.map(that.data["items"].objects, function(i) { return i.get(p); }); | |
| return fn.apply(this, values); | |
| } | |
| var minX = aggregate(properties[0], Math.min); | |
| var maxX = aggregate(properties[0], Math.max); | |
| var minY = aggregate(properties[1], Math.min); | |
| var maxY = aggregate(properties[1], Math.max); | |
| function x(val) { | |
| return (((val-minX) * $('#canvas').width()) / (maxX-minX)); | |
| } | |
| function y(val) { | |
| return (((val-minY) * $('#canvas').height()) / (maxY-minY)); | |
| } | |
| // Apply layout | |
| this.data["items"].each(function(item, key, index) { | |
| item.pos = { | |
| x: x(item.get(properties[0])), | |
| y: y(item.get(properties[1])) | |
| }; | |
| }); | |
| }, | |
| update: function(items, properties) { | |
| this.data["items"] = items; | |
| this.layout(properties); | |
| this.refresh(); | |
| } | |
| }); | |
| exports.Scatterplot = Scatterplot; | |
| })(window); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment