<html>
<head>
<link class="jsbin" href="https://getbootstrap.com/2.3.2/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css" />
<link class="jsbin" href="https://getbootstrap.com/2.3.2/assets/css/bootstrap.css" rel="stylesheet" type="text/css" />
<script class="jsbin" src="https://code.jquery.com/jquery-1.7.2.min.js"></script>
<script class="jsbin" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script class="jsbin" src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone-min.js"></script>
<script src="https://js-hypercube-demo.herokuapp.com/js-hypercube.min.js"></script>
<script src="https://js-hypercube-demo.herokuapp.com/example.data.js"></script>
<meta charset=utf-8 />
<title>js-hypercube/backbone.js example</title>
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
article, aside, figure, footer, header, hgroup,
menu, nav, section { display: block; }
td {height:50px;vertical-align:top;}
</style>
</head>
<body>
<div class="container">
<h1>Video Game Revenue Example</h1>
<div class="row">
<div class="span12">
<table class="table table-condensed" id="revenue"></table>
</div>
</div>
</div>
</body>
</html>
// convert timestamp to multiple date/time dimensions
ps.Cube.transforms.dateLocal(window.example.data);
var sampleCube = ps.Cube.deserialize(window.example.data, ['rentals', 'sales', 'revenue']);
// an OLAP cube
var Cube = Backbone.Model.extend({
defaults: {
slice: 'Total Revenue',
drillBy: null, // dimension to drill by
childSlices: null, // child cubes if we've drilled down
parentSlices: [] // any dimensions we are already slicing by
},
initialize: function() {
// when drilling by a different dimension, update children
this.bind('change:drillBy', function() {
this.updateChildCubes();
});
},
updateChildCubes: function() {
var drillBy = this.get('drillBy');
if (drillBy === null) {
// remove children
this.set({childSlices: null});
} else {
var cube = this.get('cube');
var allSlices = _.toArray(_.clone(this.get('parentSlices')));
allSlices.push(drillBy);
var childCubes = _.map(cube.getValues(drillBy).sort(), function(element) {
var slice = {};
slice[drillBy] = element;
return new Cube({
cube: cube.slice(slice),
slice: element,
parentSlices: allSlices
});
});
this.set({childSlices: new CubeList(childCubes)});
}
},
drillBy: function(dimension) {
this.set({drillBy: dimension});
return this;
},
// get next dimension available to drill down by
nextDimension: function() {
var allDimensions = this.get('cube').getFactNames();
var allSlices = this.get('parentSlices');
// discard dimensions in parent slices
var dimensions = _.difference(allDimensions, allSlices);
if (dimensions.length === 0) {
// can't drill down any further
return false;
}
var currentDrill = this.get('drillBy');
if (currentDrill === null) {
return dimensions[0];
} else {
var pos = _.indexOf(dimensions, currentDrill);
if (pos == dimensions.length-1) {
return null;
} else {
return dimensions[pos + 1];
}
}
},
drillByNextDimension: function() {
var nextDimension = this.nextDimension();
if (nextDimension === false) {
return;
}
this.drillBy(nextDimension);
}
});
// used to hold all of the child cubes when we drill down
var CubeList = Backbone.Collection.extend({
model: Cube
});
// render the total revenue for a cube
var CubeView = Backbone.View.extend({
tagName: 'tr',
className: 'bullet',
initialize: function() {
console.log('initializing cubeview');
_.bindAll(this, 'render', 'drill');
this.model.bind('change', this.render);
},
// drill down on click
events: {
'click': 'drill'
},
drill: function(){
event.stopImmediatePropagation();
this.model.drillByNextDimension();
},
render: function() {
// get the underlying js-hybercube object
var cube = this.model.get('cube');
var revenue = cube.sum().rentals;
var slice = this.model.get('slice').toString();
// render the revenue and bar chart in a table row
// my html/css skills are as bad as they were in 1999
$(this.el).html('<td><button class="btn btn-small btn-primary">' +
slice + '</button> <span class="badge badge-success">$' +
revenue + '</span></td>' +
'<td class="bullet"><div style="width:'+ parseInt(revenue/10, 10) +'px;' +
'height:20px; background-color:#CCC;"></div></td>');
// render the children if we've drilled down
var childCubes = this.model.get('childSlices');
if (childCubes !== null) {
$('td.bullet', this.el).append('<h4>Drill By '+this.model.get('drillBy').toString().replace(/_/g,' ') +'</h4>');
var childView = new CubeListView({collection: childCubes});
$('td.bullet', this.el).append(childView.render().el);
}
return this;
}
});
// render a collection of cubes
var CubeListView = Backbone.View.extend({
tagName: 'table',
initialize: function() {
_.bindAll(this, 'render');
},
render: function() {
var table = this.el;
_(this.collection.models).each(function(item) {
var cubeview = new CubeView({ model: item});
$(table).append(cubeview.render().el);
}, this);
return this;
}
});
var cube = new Cube({cube: sampleCube});
var salesCube = new CubeView({
model: cube
});
$('table#revenue').append(salesCube.render().el);
Output
300px
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |