interactive dashboards
We'll add a loose layer
around your existing D3 work
Application template
<script type="text/x-handlebars">
<header class="title">
<h1>Ember and D3</h1>
<h2>Scaffolding</h2>
</header>
<div class="content">
<div id="left-panel">
<h3>The datepicker</h3>
</div>
<div id="center-panel">
{{outlet}}
</div>
</div>
</script>
Index template
<script type="text/x-handlebars" data-template-name="index">
<h3>Select a month</h3>
</script>
<script>
App = Ember.Application.create();
</script>
App.Router.map(function() {
this.resource('monthlyReport', { path: '/:monthlyReport_id' });
});
App.MonthlyReport = DS.Model.extend({ companies: DS.hasMany('company', { async: true }),
date: function() { return moment( this.get('id'), 'MMM-YYYY' ); }.property('model'), });
App.Company = DS.Model.extend({ monthlyReport: DS.belongsTo('monthly-report'), name: DS.attr('string'), newContracts: DS.attr('number'), feeIncreases: DS.attr('number'), attritions: DS.attr('number'),
});
// Generate some random test data, then
App.MonthlyReport.FIXTURES = months; App.Company.FIXTURES = companies;
App.MonthlyDatepickerComponent = Ember.Component.extend({ classNames: ['dp'], didInsertElement: function() { var _this = this; this.$().datepicker({format: 'M-yyyy',minViewMode: 'months'}) .on('changeDate', function(e) { _this.sendAction('action', e.format()); }); this.update(); },
update: function() { if (this.get('month')) { this.$().datepicker('update', this.get('month').toDate()); } else { this.$('.month.active').removeClass('active'); } }.observes('month') });
App.ApplicationController = Ember.Controller.extend({
needs: ['monthlyReport']
});
{{monthly-datepicker
month=controller.controllers.monthlyReport.date
action="getMonthlyReport"}}
App.ApplicationController = Ember.Controller.extend({ needs: ['monthlyReport'], actions: { getMonthlyReport: function(id) {
this.transitionToRoute(
'monthlyReport',
this.get('store').find('monthlyReport', id )
);
} } });
App.MonthlyReportController = Ember.ObjectController.extend({
title: function() {
return this.get('date').format('MMMM YYYY');
}.property('model')
});
<script type="text/x-handlebars" data-template-name="monthlyReport">
<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')) {return;} var data = this.map(function(company) { return { category: company.get('name'), count: company.get('newContracts'), }; }); return data; }.property('model') });
App.MonthlyReportController = Ember.ObjectController.extend({ needs: ['companies'],
... });
App.BarChartComponent = Ember.Component.extend({
classNames: ['chart'],
chart: BarChart()
.margin({left: 40, top: 40, bottom: 80, right: 40})
.manyColors(true)
.colors(['#be3600', '#ff4b00', '#ff6100', '#ff7600', '#ff8c00'])
// .oneColor('#BE3600')
.rotateAxisLabels(true)
// .hideAxisLabels(true)
// .noTicks(true)
// .staticDataLabels(true)
,
didInsertElement: function() {
Ember.run.once(this, 'update');
},
update: function() {
if (this.get('isLoaded')) {
d3.select(this.$()[0])
.data([ this.get('data') ])
.call(this.get('chart'));
}
}.observes('data')
});
{{bar-chart
data=controller.controllers.companies.data
isLoaded=controller.controllers.companies.model.isLoaded }}
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', 'filter')
});
<ul class="nav nav-pills filters">
{{filter-item value="newContracts"
label="New Contracts"
filter=controller.controllers.companies.filter}}
{{filter-item value="feeIncreases"
label="Fee Increases"
filter=controller.controllers.companies.filter}}
{{filter-item value="attritions"
label="Attritions"
filter=controller.controllers.companies.filter}}
</ul>
App.FilterItemComponent = Ember.Component.extend({
tagName: 'li',
classNameBindings: ['active'],
active: function() {
return this.get('filter') == this.get('value');
}.property('filter'),
click: function() {
this.set('filter', this.get('value'));
}
});
App.PieChartComponent = Ember.Component.extend({
classNames: ['chart'],
chart: PieChart()
.oneColor('#BE3600')
.labelColor('white')
.labelSize('11px'),
didInsertElement: function() {
Ember.run.once(this, 'update');
},
update: function() {
if (this.get('isLoaded')) {
d3.select(this.$()[0])
.data([ this.get('data') ])
.call(this.get('chart'));
}
}.observes('data')
});
<div class="row">
<div class="col-lg-7">
{{bar-chart
data=controller.controllers.companies.data
isLoaded=controller.controllers.companies.model.isLoaded }}
</div>
<div class="col-lg-5">
{{pie-chart
data=controller.controllers.companies.data
isLoaded=controller.controllers.companies.model.isLoaded}}
</div>
</div>