Skip to content

Commit

Permalink
First draft of outing statistics #390
Browse files Browse the repository at this point in the history
  • Loading branch information
cbeauchesne committed Mar 23, 2021
1 parent 41be420 commit e3142bf
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 22 deletions.
45 changes: 45 additions & 0 deletions src/js/apis/c2c/DocumentService.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,51 @@ DocumentService.prototype.getAll = function (params) {
return this.api.get('/' + this.documentType + 's', { params });
};

DocumentService.prototype.fullDownload = function (params, limit, progress) {
// will load the ENTIRE list of document. Limited to 2000 docs
const this_ = this;

limit = limit || 2000;
params = { ...params }; // clone

return new Promise((resolve, reject) => {
const result = [];

params.limit = 100;

const download = function (offset) {
params.offset = offset;

this_
.getAll(params)
.then((response) => {
for (const document of response.data.documents) {
result.push(document);
}

if (progress) {
progress(result.length, response.data.total);
}

if (response.data.documents.length === 0) {
resolve(result);
} else if (result.length === response.data.total) {
resolve(result);
} else if (result.length >= limit) {
resolve(result);
} else {
download(offset + 100);
}
})
.catch((error) => {
reject(error);
});
};

download(0);
});
};

DocumentService.prototype.get = function (id, lang) {
return this.api.get('/' + this.documentType + 's/' + id, { params: { l: lang } });
};
Expand Down
2 changes: 2 additions & 0 deletions src/js/vue-plugins/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import WaypointView from '@/views/document/WaypointView';
import XreportView from '@/views/document/XreportView';
import DashboardView from '@/views/portals/DashboardView';
import FeedView from '@/views/portals/FeedView';
import OutingsStatsView from '@/views/portals/OutingsStatsView';
import YetiView from '@/views/portals/YetiView';
import NotFoundView from '@/views/static-views/NotFoundView';
import SeracView from '@/views/static-views/SeracView';
Expand Down Expand Up @@ -60,6 +61,7 @@ const routes = [
{ path: '/following', name: 'following', component: FollowingView },
{ path: '/preferences', name: 'preferences', component: PreferencesView },
{ path: '/yeti/:document_id(\\d+)?/:page?', name: 'yeti', component: YetiView },
{ path: '/outings-stats', name: 'outings-stats', component: OutingsStatsView },

{ path: '/wip', name: 'workinprogress', component: WorkInProgressView },

Expand Down
32 changes: 10 additions & 22 deletions src/views/document/utils/OutingsDownloader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export default {
methods: {
downloadOutings() {
this.isLoading = true;
const outings = [];
const extraKeys = new Map([
['title', this.$documentUtils.getDocumentTitle],
Expand All @@ -38,27 +37,16 @@ export default {
],
]);
const download = function (offset) {
c2c.outing
.getAll({ u: this.profileId, limit: 50, offset })
.then((response) => {
for (const document of response.data.documents) {
outings.push(document);
}
if (response.data.documents.length === 0 || outings.length === response.data.total) {
utils.downloadCsv(outings, 'outings.csv', extraKeys);
this.isLoading = false;
} else {
download(offset + 50);
}
})
.catch((error) => {
this.isLoading = false;
window.alert(error.response.data.errors[0].description);
});
}.bind(this);
download(0);
c2c.outing
.fullDownload({ u: this.profileId }, 1000)
.then((outings) => {
utils.downloadCsv(outings, 'outings.csv', extraKeys);
this.isLoading = false;
})
.catch((error) => {
this.isLoading = false;
window.alert(error.response.data.errors[0].description);
});
},
},
};
Expand Down
68 changes: 68 additions & 0 deletions src/views/portals/OutingsStatsView.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<div class="section">
<h1>
<span>Outing statistics</span>
<span v-if="!outings">{{ Math.round(loadingPercentage * 100) }}%</span>
</h1>
<div v-if="outings" class="columns">
<div class="column">
<h2>By year</h2>
<div ref="year_repartition"></div>
</div>
<div class="column">
<h2>By month</h2>
<div ref="month_repartition"></div>
</div>
</div>
</div>
</template>

<script>
import { createHistogram } from './utils/outings-stats';
import c2c from '@/js/apis/c2c';
import d3 from '@/js/libs/d3';
const getOutingYear = function (outing) {
return parseInt(outing.date_start.substring(0, 4), 10);
};
const getOutingMonth = function (outing) {
return parseInt(outing.date_start.substring(5, 7), 10);
};
export default {
data() {
return {
outings: null,
loadingPercentage: 0,
};
},
watch: {
$route: {
handler: 'load',
immediate: true,
},
},
methods: {
load() {
c2c.outing.fullDownload(this.$route.query, 2000, this.progress).then((outings) => {
this.outings = outings;
d3.then(this.createGraphs);
});
},
progress(current, total) {
this.loadingPercentage = current / total;
},
createGraphs() {
const outings = this.outings;
createHistogram(d3, outings, this.$refs.year_repartition, getOutingYear);
createHistogram(d3, outings, this.$refs.month_repartition, getOutingMonth);
},
},
};
</script>
64 changes: 64 additions & 0 deletions src/views/portals/utils/outings-stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export function createHistogram(d3, outings, htmlElement, aggregationFuntion) {
// set the dimensions and margins of the graph
var margin = { top: 10, right: 30, bottom: 30, left: 40 },
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3
.select(htmlElement)
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

// X axis: scale and draw:
var x = d3
.scaleLinear()
.domain([d3.min(outings, aggregationFuntion), d3.max(outings, aggregationFuntion) + 1]) // can use this instead of 1000 to have the max of data:
.range([0, width]);

svg
.append('g')
.attr('transform', 'translate(0,' + height + ')')
.call(d3.axisBottom(x));

// set the parameters for the histogram
var histogram = d3
.histogram()
.value(aggregationFuntion) // I need to give the vector of value
.domain(x.domain()); // then the domain of the graphic

// And apply this function to data to get the bins
var bins = histogram(outings);

// Y axis: scale and draw:
var y = d3.scaleLinear().range([height, 0]);
y.domain([
0,
d3.max(bins, function (d) {
return d.length;
}),
]); // d3.hist has to be called before the Y axis obviously

svg.append('g').call(d3.axisLeft(y));

// append the bar rectangles to the svg element
svg
.selectAll('rect')
.data(bins)
.enter()
.append('rect')
.attr('x', 1)
.attr('transform', function (d) {
return 'translate(' + x(d.x0) + ',' + y(d.length) + ')';
})
.attr('width', function (d) {
return x(d.x1) - x(d.x0) - 1;
})
.attr('height', function (d) {
return height - y(d.length);
})
.style('fill', '#69b3a2');
}

0 comments on commit e3142bf

Please sign in to comment.