From 1b83b547430a4dfc0b793bc32345a94a42dcc3b1 Mon Sep 17 00:00:00 2001 From: mateuswetah Date: Thu, 11 Mar 2021 14:29:24 -0300 Subject: [PATCH] Improvements to heatmap construction. #483. --- src/assets/css/tainacan-reports.css | 6 +- src/assets/css/tainacan-reports.css.map | 2 +- ...class-tainacan-rest-reports-controller.php | 2 +- .../admin/js/store/modules/report/actions.js | 21 ++++ .../admin/js/store/modules/report/getters.js | 8 ++ .../admin/js/store/modules/report/index.js | 13 ++ .../js/store/modules/report/mutations.js | 8 ++ src/views/reports/pages/reports-list.vue | 119 +++++++++++++++++- 8 files changed, 172 insertions(+), 7 deletions(-) diff --git a/src/assets/css/tainacan-reports.css b/src/assets/css/tainacan-reports.css index faeafd376..cafea97d9 100644 --- a/src/assets/css/tainacan-reports.css +++ b/src/assets/css/tainacan-reports.css @@ -1,4 +1,6 @@ -#tainacan-reports-app .tainacan-icon::before { - opacity: 0.0; } +#tainacan-reports-app { + margin: 10px 2px 10px 2px; } + #tainacan-reports-app .tainacan-icon::before { + opacity: 0.0; } /*# sourceMappingURL=tainacan-reports.css.map */ diff --git a/src/assets/css/tainacan-reports.css.map b/src/assets/css/tainacan-reports.css.map index 8f58aeaf8..3a956c1cc 100644 --- a/src/assets/css/tainacan-reports.css.map +++ b/src/assets/css/tainacan-reports.css.map @@ -1,6 +1,6 @@ { "version": 3, -"mappings": "AAEI,4CAAuB;EACnB,OAAO,EAAE,GAAG", +"mappings": "AAAA,qBAAsB;EAClB,MAAM,EAAE,iBAAiB;EAGzB,4CAAuB;IACnB,OAAO,EAAE,GAAG", "sources": ["../../views/reports/tainacan-reports.scss"], "names": [], "file": "tainacan-reports.css" diff --git a/src/classes/api/endpoints/class-tainacan-rest-reports-controller.php b/src/classes/api/endpoints/class-tainacan-rest-reports-controller.php index 4a8f250ab..790cd1346 100644 --- a/src/classes/api/endpoints/class-tainacan-rest-reports-controller.php +++ b/src/classes/api/endpoints/class-tainacan-rest-reports-controller.php @@ -485,7 +485,7 @@ class REST_Reports_Controller extends REST_Controller { $response['totals'] = array( 'last_year' => array( - 'genreal' => $this->get_activities_general($collection_id), + 'general' => $this->get_activities_general($collection_id), 'by_user' => $this->get_activities_general_by_user($collection_id) ), 'by_user' => $this->get_activities_users($collection_id) diff --git a/src/views/admin/js/store/modules/report/actions.js b/src/views/admin/js/store/modules/report/actions.js index ec1bcce84..10c2555c2 100644 --- a/src/views/admin/js/store/modules/report/actions.js +++ b/src/views/admin/js/store/modules/report/actions.js @@ -109,4 +109,25 @@ export const fetchTaxonomyTerms = ({ commit }, taxonomyId) => { }) .catch(error => reject(error)); }); +}; + +export const fetchActivities = ({ commit }, { collectionId } ) => { + + let endpoint = '/reports'; + + if (collectionId && collectionId != 'default') + endpoint += '/collection/' + collectionId + '/activities'; + else + endpoint += '/activities'; + + return new Promise((resolve, reject) => { + axios.tainacan.get(endpoint) + .then(res => { + let activities = res.data; + + commit('setActivities', activities); + resolve(activities); + }) + .catch(error => reject(error)); + }); }; \ No newline at end of file diff --git a/src/views/admin/js/store/modules/report/getters.js b/src/views/admin/js/store/modules/report/getters.js index f32f284cc..e88c00324 100644 --- a/src/views/admin/js/store/modules/report/getters.js +++ b/src/views/admin/js/store/modules/report/getters.js @@ -22,6 +22,10 @@ export const getTaxonomyTerms = state => { return state.taxonomyTerms; }; +export const getActivities = state => { + return state.activities; +}; + export const getStackedBarChartOptions = state => { return state.stackedBarChartOptions; }; @@ -33,3 +37,7 @@ export const getHorizontalBarChartOptions = state => { export const getDonutChartOptions = state => { return state.donutChartOptions; }; + +export const getHeatMapChartOptions = state => { + return state.heatMapChartOptions; +}; diff --git a/src/views/admin/js/store/modules/report/index.js b/src/views/admin/js/store/modules/report/index.js index 2db9ce396..af9b92809 100644 --- a/src/views/admin/js/store/modules/report/index.js +++ b/src/views/admin/js/store/modules/report/index.js @@ -9,6 +9,7 @@ const state = { taxonomyTerms: {}, metadata: {}, metadataList: {}, + activities: {}, stackedBarChartOptions: { chart: { type: 'bar', @@ -132,6 +133,18 @@ const state = { horizontalAlign: 'left', offsetX: 40, } + }, + heatMapChartOptions: { + chart: { + height: 350, + type: 'heatmap', + }, + dataLabels: { + enabled: false + }, + title: { + text: '' + }, } }; diff --git a/src/views/admin/js/store/modules/report/mutations.js b/src/views/admin/js/store/modules/report/mutations.js index 236be7dfa..ca567bcb3 100644 --- a/src/views/admin/js/store/modules/report/mutations.js +++ b/src/views/admin/js/store/modules/report/mutations.js @@ -22,6 +22,10 @@ export const setTaxonomyTerms = (state, taxonomyTerms) => { state.taxonomyTerms = taxonomyTerms; }; +export const setActivities = (state, activities) => { + state.activities = activities; +}; + export const setStackedBarChartOptions = (state, stackedBarChartOptions) => { state.stackedBarChartOptions = stackedBarChartOptions; }; @@ -32,4 +36,8 @@ export const setHorizontalBarChartOptions = (state, horizontalBarChartOptions) = export const setDonutChartOptions = (state, donutChartOptions) => { state.donutChartOptions = donutChartOptions; +}; + +export const setHeatMapChartOptions = (state, heatMapChartOptions) => { + state.heatMapChartOptions = heatMapChartOptions; }; \ No newline at end of file diff --git a/src/views/reports/pages/reports-list.vue b/src/views/reports/pages/reports-list.vue index f2d2724a1..0db8f8266 100644 --- a/src/views/reports/pages/reports-list.vue +++ b/src/views/reports/pages/reports-list.vue @@ -170,6 +170,21 @@ style="min-height=380px" class="skeleton postbox" /> +
+ +
+
@@ -191,6 +206,7 @@ export default { isFetchingTaxonomyTerms: false, isFetchingMetadata: false, isFetchingMetadataList: false, + isFetchingActivities: false, collectionsListChartSeries: [], collectionsListChartOptions: {}, taxonomiesListChartSeries: [], @@ -203,7 +219,9 @@ export default { metadataTypeChartOptions: {}, metadataDistributionChartSeries: [], metadataDistributionChartOptions: {}, - metadataDistributionChartHeight: 730 + metadataDistributionChartHeight: 730, + activitiesChartSeries: [], + activitiesChartOptions: {} } }, computed: { @@ -217,9 +235,11 @@ export default { taxonomyTerms: 'getTaxonomyTerms', taxonomiesList: 'getTaxonomiesList', collectionsList: 'getCollectionsList', + activities: 'getActivities', stackedBarChartOptions: 'getStackedBarChartOptions', donutChartOptions: 'getDonutChartOptions', - horizontalBarChartOptions: 'getHorizontalBarChartOptions' + horizontalBarChartOptions: 'getHorizontalBarChartOptions', + heatMapChartOptions: 'getHeatMapChartOptions' }), taxonomiesListArray() { return this.taxonomiesList && this.taxonomiesList != undefined ? Object.values(this.taxonomiesList) : []; @@ -234,6 +254,7 @@ export default { this.selectedCollection = to['collection'] ? to['collection'] : 'default'; this.loadSummary(); this.loadMetadata(); + this.loadActivities(); if (!this.selectedCollection || this.selectedCollection == 'default') { this.loadCollectionsList(); @@ -269,7 +290,8 @@ export default { 'fetchTaxonomiesList', 'fetchTaxonomyTerms', 'fetchMetadata', - 'fetchMetadataList' + 'fetchMetadataList', + 'fetchActivities' ]), loadCollections() { this.isFetchingCollections = true; @@ -578,6 +600,97 @@ export default { this.isFetchingMetadataList = false; }) .catch(() => this.isFetchingMetadataList = false); + }, + loadActivities() { + this.isFetchingActivities = true; + this.fetchActivities({ collectionId: this.selectedCollection }) + .then(() => { + + const daysWithActivities = this.activities && this.activities.totals && this.activities.totals.last_year && this.activities.totals.last_year.general ? this.activities.totals.last_year.general : []; + if (daysWithActivities && daysWithActivities.length) { + + let everyDayOfTheYear = Array.from(new Array(7), + (val,index) => { + return { + name: (index + 1), + data: new Array(53).fill({x: '', y: 0}) + } + } + ); + + const firstDayOfTheWeekWithActivity = parseInt(daysWithActivities[0].day_of_week); + let dayWithActivityIndex = 0; + let daysToSkip = 0; + + // Loop for each column (number of the week in the year) + for (let column = 0; column < 53; column++) { + + // Loop for each line (number of the day in the week) + for (let line = 0; line < 7; line++) { + + // If there are no more days with activities, get outta here + if (dayWithActivityIndex >= daysWithActivities.length) + break; + + // We should only begin inserting days from firstDayOfTheWeekWithActivity + if (column == 0 && line < firstDayOfTheWeekWithActivity - 1) { + continue; + + // On the first day, we don't need to calculate distances, just set the value and save the date + } else if (column == 0 && line == firstDayOfTheWeekWithActivity - 1) { + everyDayOfTheYear[line].data[column] = { + x: '', + y: parseInt(daysWithActivities[dayWithActivityIndex].total) + }; + + const lastDayWithActivity = new Date(daysWithActivities[dayWithActivityIndex].year, daysWithActivities[dayWithActivityIndex].month - 1, daysWithActivities[dayWithActivityIndex].day); + dayWithActivityIndex++; + + const nextDayWithActivity = new Date(daysWithActivities[dayWithActivityIndex].year, daysWithActivities[dayWithActivityIndex].month - 1, daysWithActivities[dayWithActivityIndex].day); + + daysToSkip = Math.floor( (nextDayWithActivity - lastDayWithActivity) / (1000 * 60 * 60 * 24) ); + } else { + daysToSkip--; + + // If we don't have more days to skip, time to update values + if ( daysToSkip <= 0) { + everyDayOfTheYear[line].data[column] = { + x: '', + y: parseInt(daysWithActivities[dayWithActivityIndex].total) + }; + + const lastDayWithActivity = new Date(daysWithActivities[dayWithActivityIndex].year, daysWithActivities[dayWithActivityIndex].month - 1, daysWithActivities[dayWithActivityIndex].day); + dayWithActivityIndex++; + + const nextDayWithActivity = new Date(daysWithActivities[dayWithActivityIndex].year, daysWithActivities[dayWithActivityIndex].month - 1, daysWithActivities[dayWithActivityIndex].day); + + daysToSkip = Math.floor( (nextDayWithActivity - lastDayWithActivity) / (1000 * 60 * 60 * 24) ); + console.log(daysToSkip, nextDayWithActivity, lastDayWithActivity); + } + } + } + } + + this.activitiesChartSeries = everyDayOfTheYear(); + this.activitiesChartOptions = { + ...this.heatMapChartOptions, + title: { + text: this.$i18n.get('label_activities_last_year') + }, + } + } else { + this.activitiesChartSeries = []; + this.activitiesChartOptions = { + ...this.heatMapChartOptions, + title: { + text: this.$i18n.get('label_activities_last_year') + }, + } + } + + this.isFetchingActivities = false; + }) + .catch(() => this.isFetchingActivities = false); } } }