Skip to content

Commit 7f7e296

Browse files
committed
Merge pull request #293 from apinf/feature/pagination-datatable
Feature/pagination datatable
2 parents 8237aeb + a094007 commit 7f7e296

File tree

6 files changed

+208
-98
lines changed

6 files changed

+208
-98
lines changed

.meteor/packages

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,4 @@ charts:dc
7171
cfs:filesystem
7272
dapearce:material-icons
7373
mrt:flash-messages
74+
frenchbread:dynatable

.meteor/versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ email@1.0.6
5656
fastclick@1.0.3
5757
favorites@0.0.4
5858
fortawesome:fontawesome@4.3.0
59+
frenchbread:dynatable@0.1.0
5960
frenchbread:elastic-rest@0.2.0
6061
geojson-utils@1.0.3
6162
github@1.1.3

client/charts/charts.js

Lines changed: 188 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -22,124 +22,223 @@ Template.chartsLayout.rendered = function () {
2222
'request_path'
2323
]
2424
};
25-
26-
drawChart(input);
25+
// Drawing the chart
26+
drawChart(input)
2727
};
2828

2929
Template.chartsLayout.created = function () {
3030

31+
// function that sets chart data to be available in template
3132
drawChart = function (input) {
3233

3334
Meteor.call("getChartData", input, function (err, data) {
35+
36+
// error checking
3437
if (err) {
3538

3639
// removing loading state once loaded
3740
$('#loadingState').html("Loaded");
3841
alert("Data is not found!");
3942

4043
} else {
44+
// Parse the returned data for DC
45+
var parsedData = parseData(data);
4146

42-
var items = data.hits.hits;
47+
// Render the charts using parsed data
48+
renderCharts(parsedData);
4349

44-
var index = new crossfilter(items);
50+
}
51+
});
52+
};
4553

46-
var dateFormat = d3.time.format.iso;
47-
items.forEach(function (d) {
54+
// function that parses chart data
55+
parseData = function (data) {
56+
// Get chart data from within data object
57+
var items = data.hits.hits;
4858

49-
var timeStamp = moment(d.fields.request_at[0]);
50-
timeStamp = timeStamp.format();
51-
d.fields.ymd = dateFormat.parse(timeStamp);
52-
d.fields.itemsCount = +data.hits.total;
59+
// Create CrossFilter index using chart data
60+
var index = new crossfilter(items);
5361

62+
// Create ISO date format
63+
var dateFormat = d3.time.format.iso;
5464

55-
});
65+
// Parse each item adding timestamp as YMD and count the items
66+
items.forEach(function (d) {
67+
// Parse timestamp to Moment .jsobject
68+
var timeStamp = moment(d.fields.request_at[0]);
5669

57-
var timeStampDimension = index.dimension(function(d){ return d.fields.ymd; });
58-
var countryDimension = index.dimension(function (d) { return d.fields.request_ip_country });
70+
// Format the timestamp using Moment.js format method
71+
timeStamp = timeStamp.format();
5972

60-
var timeStampGroup = timeStampDimension.group();
61-
var countryGroup = countryDimension.group();
62-
var all = index.groupAll();
73+
// Add YMD field to item
74+
d.fields.ymd = dateFormat.parse(timeStamp);
6375

64-
dc.dataCount("#row-selection")
65-
.dimension(index)
66-
.group(all);
76+
// Add item count from total hits
77+
d.fields.itemsCount = +data.hits.total;
78+
});
6779

68-
var totalCountries = countryGroup.reduceSum(function(d) {
69-
return d.fields.itemsCount;
70-
});
80+
// Create timestamp dimension from YMD field
81+
var timeStampDimension = index.dimension(function(d){ return d.fields.ymd; });
7182

72-
var minDate = d3.min(items, function(d) { return d.fields.ymd; });
73-
var maxDate = d3.max(items, function(d) { return d.fields.ymd; });
74-
75-
var timeScale = d3.time.scale().domain([minDate, maxDate]);
76-
var countryScale = d3.scale.ordinal().domain(countryDimension);
77-
78-
var chart = dc.lineChart("#line-chart");
79-
var countryChart = dc.barChart("#bar-chart");
80-
var dataTable = dc.dataTable("#data-table");
81-
var overview = dc.barChart("#overview-chart");
82-
83-
chart
84-
.width(1140)
85-
.height(480)
86-
.transitionDuration(1500)
87-
.elasticY(true)
88-
.x(timeScale)
89-
.dimension(timeStampDimension)
90-
.group(timeStampGroup)
91-
.mouseZoomable(true)
92-
.rangeChart(overview)
93-
.renderArea(true)
94-
.dotRadius(3)
95-
.brushOn(false)
96-
.renderHorizontalGridLines(true)
97-
.renderVerticalGridLines(true);
98-
99-
overview
100-
.width(1140)
101-
.height(40)
102-
.margins({top: 0, right: 50, bottom: 20, left: 40})
103-
.dimension(timeStampDimension)
104-
.group(timeStampGroup)
105-
.centerBar(true)
106-
.gap(1)
107-
.x(d3.time.scale().domain([new Date(2015, 1, 1), new Date()]))
108-
.alwaysUseRounding(true)
109-
.yAxis().ticks(0);
110-
111-
countryChart
112-
.width(1140)
113-
.height(250)
114-
.dimension(countryDimension)
115-
.group(totalCountries)
116-
.x(countryScale)
117-
.xUnits(dc.units.ordinal)
118-
.renderHorizontalGridLines(true)
119-
.renderVerticalGridLines(true);
120-
121-
dataTable.width(960).height(800)
122-
.dimension(timeStampDimension)
123-
.group(function(d) { return "Logs"
124-
})
125-
.size(100) // number of rows to return
126-
.columns([
127-
function(d) { return d.fields.ymd; },
128-
function(d) { return d.fields.request_ip_country; },
129-
function(d) { return d.fields.request_ip; },
130-
function(d) { return d.fields.response_time; },
131-
function(d) { return d.fields.request_path; }
132-
])
133-
.sortBy(function(d){ return -d.fields.ymd; })
134-
.order(d3.ascending);
83+
// Create country dimension from Request IP Country field
84+
var countryDimension = index.dimension(function (d) { return d.fields.request_ip_country });
13585

136-
// removing loading state once loaded
137-
$('#loadingState').html("Loaded! Took <b>" + data.took + "</b>ms");
86+
// Group entries by timestamp dimension
87+
var timeStampGroup = timeStampDimension.group();
13888

139-
dc.renderAll();
89+
// Group entries by country
90+
var countryGroup = countryDimension.group();
14091

141-
}
92+
// Create index by all dimensions
93+
var all = index.groupAll();
94+
95+
// Providing information about current data selection
96+
dc.dataCount("#row-selection")
97+
.dimension(index)
98+
.group(all);
99+
100+
// total amount of countries within filtering
101+
var totalCountries = countryGroup.reduceSum(function(d) {
102+
return d.fields.itemsCount;
142103
});
104+
105+
// set up a range of dates for charts
106+
var minDate = d3.min(items, function(d) { return d.fields.ymd; });
107+
var maxDate = d3.max(items, function(d) { return d.fields.ymd; });
108+
109+
// Create time scale from min and max dates
110+
var timeScale = d3.time.scale().domain([minDate, maxDate]);
111+
112+
// Create country scale from country dimension
113+
var countryScale = d3.scale.ordinal().domain(countryDimension);
114+
115+
116+
// Return object with all key values created above
117+
return {
118+
timeStampDimension : timeStampDimension,
119+
countryDimension : countryDimension,
120+
timeStampGroup : timeStampGroup,
121+
countryGroup : countryGroup,
122+
totalCountries : totalCountries,
123+
timeScale : timeScale,
124+
countryScale : countryScale,
125+
took : data.took
126+
};
143127
}
144128

129+
renderCharts = function (parsedData) {
130+
131+
var timeStampDimension = parsedData.timeStampDimension;
132+
var countryDimension = parsedData.countryDimension;
133+
var timeStampGroup = parsedData.timeStampGroup;
134+
var countryGroup = parsedData.countryGroup;
135+
var totalCountries = parsedData.totalCountries;
136+
var timeScale = parsedData.timeScale;
137+
var countryScale = parsedData.countryScale;
138+
var took = parsedData.took;
139+
140+
var chart = dc.lineChart("#line-chart");
141+
var countryChart = dc.barChart("#bar-chart");
142+
143+
chart
144+
.width(1140)
145+
.height(480)
146+
.elasticX(true)
147+
.x(timeScale)
148+
.dimension(timeStampDimension)
149+
.group(timeStampGroup)
150+
.renderArea(true)
151+
.dotRadius(3)
152+
.renderHorizontalGridLines(true)
153+
.renderVerticalGridLines(true);
154+
155+
countryChart
156+
.width(1140)
157+
.height(250)
158+
.dimension(countryDimension)
159+
.group(totalCountries)
160+
.x(countryScale)
161+
.xUnits(dc.units.ordinal)
162+
.renderHorizontalGridLines(true)
163+
.renderVerticalGridLines(true);
164+
165+
166+
// Creates Dynatable
167+
var dynatable = $('#dc-data-table').dynatable({
168+
features: {
169+
pushState: false
170+
},
171+
dataset: {
172+
records: setUpDataSet(),
173+
perPageDefault: 10,
174+
perPageOptions: [10, 20, 50, 100]
175+
}
176+
}).data('dynatable');
177+
178+
// Listens to filtering event and refreshes the table on a change
179+
function RefreshTable() {
180+
dc.events.trigger(function () {
181+
dynatable.settings.dataset.originalRecords = setUpDataSet();
182+
dynatable.process();
183+
});
184+
};
185+
186+
// Add each chart to the DC Chart Registry
187+
for (var i = 0; i < dc.chartRegistry.list().length; i++) {
188+
var chartI = dc.chartRegistry.list()[i];
189+
chartI.on("filtered", RefreshTable);
190+
}
191+
192+
// Parse data into array for chart
193+
function setUpDataSet() {
194+
var dataSet = [];
195+
timeStampDimension.top(Infinity).forEach(function (e) {
196+
197+
var country;
198+
var path;
199+
var request_ip;
200+
var response_time;
201+
202+
// Error handling for empty fields
203+
try{
204+
country = e.fields.request_ip_country[0]
205+
}catch(e){
206+
country = "";
207+
}
208+
209+
try{
210+
path = e.fields.request_path[0];
211+
}catch(e){
212+
path = "";
213+
}
214+
215+
try{
216+
request_ip = e.fields.request_ip[0];
217+
}catch(e){
218+
request_ip = "";
219+
}
220+
221+
try{
222+
response_time = e.fields.response_time[0];
223+
}catch(e){
224+
response_time = "";
225+
}
226+
227+
dataSet.push({
228+
"time" : e.fields.request_at[0],
229+
"country" : country,
230+
"path" : path,
231+
"ip" : request_ip,
232+
"response" : response_time
233+
});
234+
});
235+
return dataSet;
236+
}
237+
238+
RefreshTable();
239+
240+
// removing loading state once loaded
241+
$('#loadingState').html("Loaded! Took <b>" + took + "</b>ms");
242+
dc.renderAll();
243+
};
145244
};

client/charts/filter/filter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Template.filterData.events({
1+
Template.chartsLayout.events({
22
"change #filteringForm" : function(e){
33

44
// appending loading state
@@ -35,7 +35,7 @@ Template.filterData.events({
3535
]
3636
};
3737

38-
3938
drawChart(input);
39+
4040
}
4141
});

client/charts/table/table.html

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<template name="dataTable">
2-
<table class='table table-hover' id='data-table'>
2+
<table class='table table-hover' id='dc-data-table'>
33
<thead>
4-
<tr class='header'>
5-
<th>Time</th>
6-
<th>Request IP</th>
7-
<th>Request country</th>
8-
<th>Response time</th>
9-
<th>Request URL</th>
4+
<tr>
5+
<th data-dynatable-column="time" >Time stamp</th>
6+
<th data-dynatable-column="country" >Request country</th>
7+
<th data-dynatable-column="ip">Request IP</th>
8+
<th data-dynatable-column="path">Request path</th>
9+
<th data-dynatable-column="response">Response time</th>
1010
</tr>
1111
</thead>
1212
</table>

client/style/global.less

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,15 @@ html, body, h1, h2, h3, h4, h5, h6, p {
3232
border-radius: 0;
3333
}
3434

35+
/*Styles for Dynatable*/
36+
th a {
37+
color: #1c4862;
38+
}
39+
40+
.dynatable-active-page {
41+
background-color: #1c4862;
42+
}
43+
3544
.help-block {
3645
margin-bottom: 1.4em;
3746
}

0 commit comments

Comments
 (0)