<html>
<head>
<meta name="description" content="Dynamic Charts with Ember.js and D3" />
<meta charset=utf-8 />
<title>Dynamic Charts with Ember.js and D3</title>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css" rel="stylesheet">
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://builds.emberjs.com/handlebars-1.0.0-rc.4.js"></script>
<script src="http://builds.emberjs.com/ember-1.0.0-rc.5.js"></script>
<script src="http://builds.emberjs.com/ember-data-latest.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.1.6/d3.min.js"></script>
</head>
<body>
<script type="text/x-handlebars" data-template-name="application">
<h3>Dynamic Charts with Ember.js and D3</h3>
<a href="#" {{action generateNewChartValues target="controller"}} class="btn btn-info">Generate new Values</a>
{{view App.ChartView contentBinding="model"}}
</script>
</body>
</html>
App = Ember.Application.create({
ready: function() {
console.log('App ready');
}
});
App.ApplicationController = Ember.ArrayController.extend({
needs: ['chartValues'],
chartValuesBinding: 'controllers.chartValues.content',
generateNewChartValues: function() {
this.get('controllers.chartValues').send('replaceWithRandom');
}
});
App.ApplicationRoute = Ember.Route.extend({
model: function() {
var controller = this.controllerFor('chartValues');
controller.send('replaceWithRandom');
//return controller.get('content');
return App.ChartValue.find();
}
});
App.ChartView = Ember.View.extend({
chart: {},
line: {},
area: {},
updateChart: function () {
this.render();
return;
var content = this.get('content');
console.log('here', content.get('isUpdating'));
var chart = this.get('chart');
var line = this.get('line');
var area = this.get('area');
chart.selectAll('path.line')
.data(content)
.transition()
.duration(500)
.ease('sin')
.attr('d', line(content));
chart.selectAll('path.area')
.data(content)
.transition()
.duration(500)
.ease('sin')
.attr('d', area(content));
}.observes('content.[]'),
didInsertElement: function () {
},
render: function() {
var elementId = this.get('elementId');
var content = this.get('content');
console.log('here', content.get('length'));
var margin = { top: 35, right: 35, bottom: 35, left: 35};
var w = 500 - margin.right - margin.left;
var h = 300 - margin.top - margin.top;
var x = d3.scale.linear()
.range([0,w])
.domain([1,8]);
var y = d3.scale.linear()
.range([h,0])
.domain([0,130]);
var xAxis = d3.svg.axis()
.scale(x)
.ticks(10)
.tickSize(-h)
.tickSubdivide(true);
var yAxis = d3.svg.axis()
.scale(y)
.ticks(4)
.tickSize(-w)
.orient('left');
// Prepeare Chart Elements:
var line = d3.svg.line()
.interpolate('monotone')
.x(function(d) { console.log(d.get("timestamp"));
return x(d.get('timestamp'));})
.y(function(d) { return y(d.get('value'));});
this.set('line',line);
var area = d3.svg.area()
.interpolate('monotone')
.x(function(d) { return x(d.get('timestamp')); })
.y0(h)
.y1(function(d) { return y(d.get('value')); });
this.set('area',area);
var el = d3.select('#'+elementId);
el.select('svg').remove();
var chart = el.append('svg:svg')
.attr('id','chart')
.attr('width', w+margin.left+margin.right)
.attr('height', w+margin.top+margin.bottom)
.append('svg:g')
.attr('transform', 'translate('+margin.left+','+margin.top+')');
// Add Chart Elements to Chart:
chart.append('svg:g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + h + ')')
.call(xAxis);
chart.append('svg:g')
.attr('class', 'y axis')
.call(yAxis);
chart.append('svg:clipPath')
.attr('id', 'clip')
.append('svg:rect')
.attr('width', w)
.attr('height', h);
chart.append('svg:path')
.attr('class', 'area')
.attr('clip-path', 'url(#clip)')
.attr('d', area(content.toArray()));
chart.append('svg:path')
.attr('class', 'line')
.attr('clip-path', 'url(#clip)')
.attr('d', line(content.toArray()));
this.set('chart', chart);
}
});
App.ChartValuesController = Ember.ArrayController.extend({
//content: [],
replaceWithRandom: function () {
}
});
App.ChartValue = DS.Model.extend({
timestamp: DS.attr('number'),
value: DS.attr('number')
});
App.Store = DS.Store.extend({
revision: 13,
adapter: 'DS.FixtureAdapter'
});
App.ChartValue.FIXTURES = [
{
id: 1,
timestamp: 1,
value: 12.04
},
{
id: 2,
timestamp: 2,
value: 18.04
},
{
id: 3,
timestamp: 3,
value: 100.00
},
{
id: 4,
timestamp: 4,
value: 12.04
},
{
id: 5,
timestamp: 5,
value: 50.04
},
{
id: 6,
timestamp: 6,
value: 112.04
},
{
id: 7,
timestamp: 7,
value: 12.04
},
];
Output
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. |