interactive dashboards
We'll add a loose layer
around your existing D3 work
Application template
<script type="text/x-handlebars">
<div class="title">
<h1>Ember and D3</h1>
<h2>Scaffolding</h2>
</div>
<div class="content">
<div id="left-panel" class="text-center">
<h3>The datepicker</h3>
</div>
<div id="center-panel" class="container">
{{outlet}}
</div>
</div>
</script>
Index template
<script type="text/x-handlebars" data-template-name="index">
<h3 class='text-center muted thin'>Select a month</h3>
</script>
<script>
App = Ember.Application.create();
</script>
App.Router.map(function() {
this.resource('month', { path: '/:month_id' });
});
App.Store = DS.Store.extend({ adapter: DS.FixtureAdapter.create({ latency: 400 }) }); App.Month = DS.Model.extend({ test: DS.attr('number'), companies: DS.hasMany('App.Company') }); App.Company = DS.Model.extend({ month: DS.belongsTo('App.Month'), name: DS.attr('string'), newContracts: DS.attr('number'), feeIncreases: DS.attr('number'), attritions: DS.attr('number'), });
// Generate some random test data, then
App.Month.FIXTURES = months; App.Company.FIXTURES = companies;
App.ApplicationController = Ember.Controller.extend({
needs: ['month']
});
App.DatepickerView = Ember.View.extend({ classNames: ['dp'], didInsertElement: function() { var _this = this; this.$().datepicker({'format': 'M yyyy','minViewMode': 'months'}) .on('changeDate', function(e) { var id = $(this).datepicker().data('date').replace(" ", "-"); _this.get('controller').transitionToRoute(
'month', App.Month.find(id)
); }); this.$('.month.active').removeClass('active'); if (this.get('controller.controllers.month.content')) { this.update(); } },
update: function() { var month = moment(
this.get('controller.controllers.month.id') );
this.$().datepicker('hide'); this.$().datepicker('setDate', month.toDate()); this.$().datepicker('show'); }.observes('controller.controllers.month.content') });
App.MonthController = Ember.ObjectController.extend({
title: function() {
return moment(this.get('id')).format('MMMM YYYY');
}.property('model')
});
<script type="text/x-handlebars" data-template-name="month">
<h1>{{ title }}</h1>
</script>
App.LoadingRoute = Ember.Route.extend({
renderTemplate: function() { if (this.controllerFor('application').get('currentPath')) { this.render('loading', {
into: 'application',
outlet: 'loading'
}); } }
});
<script type="text/x-handlebars">
...
<div id="left-panel" class="text-center"> <div class="loading"> {{ outlet loading }} </div> {{view App.DatepickerView}} </div>
...
</script>
<script type="text/x-handlebars" data-template-name="loading">
<img src="img/loading.gif">
</script>
App.CompaniesController = Ember.ArrayController.extend({
data: function() {
if (this.get('model.isLoaded')) {
var data = this.map(function(company) {
return {
category: company.get('name'),
count: company.get('newContracts'),
};
});
}
return data;
}.property('model.isLoaded')
});
App.MonthController = Ember.ObjectController.extend({
needs: ['companies'],
title: function() {
return moment(this.get('id')).format('MMMM YYYY');
}.property('this.model')
});
App.BarGraph = Ember.View.extend({
classNames: ['chart'],
chart: BarChart()
.margin({left: 40, top: 40, bottom: 80, right: 40})
.oneColor('#BE3600')
.rotateAxisLabels(true)
// .hideAxisLabels(true)
// .noTicks(true)
// .staticDataLabels(true)
,
didInsertElement: function() {
Ember.run.once(this, 'updateChart');
},
updateChart: function() {
if (this.get('isLoaded')) {
d3.select(this.$()[0])
.data([ this.get('data') ])
.call(this.get('chart'));
}
}.observes('data')
});
{{view App.BarGraph
isLoadedBinding="controller.controllers.companies.model.isLoaded"
dataBinding="controller.controllers.companies.data"
}}
App.CompaniesController = Ember.ArrayController.extend({
filter: 'newContracts',
data: function() {
if (this.get('model.isLoaded')) {
var _this = this;
var data = this.map(function(company) {
return {
category: company.get('name'),
count: company.get( _this.get('filter') ),
};
});
}
return data;
}.property('model.isLoaded', 'filter')
});
<ul class="nav nav-pills filters"> {{#view App.FilterView value="newContracts"}} <a>New Contracts</a> {{/view}} {{#view App.FilterView value="feeIncreases"}} <a>Fee Increases</a> {{/view}} {{#view App.FilterView value="attritions"}} <a>Attritions</a> {{/view}}
</ul>
App.FilterView = Ember.View.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('controller.controllers.companies.filter') == this.get('value');
}.property('controller.controllers.companies.filter'),
click: function() {
this.get('controller.controllers.companies').set('filter', this.get('value'));
}
});
App.PieGraph = Ember.View.extend({
classNames: ['chart'],
chart: PieChart()
.oneColor('#BE3600')
.labelColor('white')
.labelSize('11px')
// .margin({left: 40, top: 40, bottom: 50, right: 40})
// .hideAxisLabels(true)
// .noTicks(true)
// .staticDataLabels(true)
,
didInsertElement: function() {
Ember.run.once(this, 'updateChart');
},
updateChart: function() {
if (this.get('isLoaded')) {
d3.select(this.$()[0])
.data([ this.get('data') ])
.call(this.get('chart'));
}
}.observes('data')
});
{{view App.PieGraph
isLoadedBinding="controller.controllers.companies.model.isLoaded"
dataBinding="controller.controllers.companies.data"
}}