Improvements to heatmap construction. #483.
This commit is contained in:
parent
3b63528305
commit
1b83b54743
|
@ -1,4 +1,6 @@
|
||||||
#tainacan-reports-app .tainacan-icon::before {
|
#tainacan-reports-app {
|
||||||
opacity: 0.0; }
|
margin: 10px 2px 10px 2px; }
|
||||||
|
#tainacan-reports-app .tainacan-icon::before {
|
||||||
|
opacity: 0.0; }
|
||||||
|
|
||||||
/*# sourceMappingURL=tainacan-reports.css.map */
|
/*# sourceMappingURL=tainacan-reports.css.map */
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"version": 3,
|
"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"],
|
"sources": ["../../views/reports/tainacan-reports.scss"],
|
||||||
"names": [],
|
"names": [],
|
||||||
"file": "tainacan-reports.css"
|
"file": "tainacan-reports.css"
|
||||||
|
|
|
@ -485,7 +485,7 @@ class REST_Reports_Controller extends REST_Controller {
|
||||||
|
|
||||||
$response['totals'] = array(
|
$response['totals'] = array(
|
||||||
'last_year' => 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_general_by_user($collection_id)
|
||||||
),
|
),
|
||||||
'by_user' => $this->get_activities_users($collection_id)
|
'by_user' => $this->get_activities_users($collection_id)
|
||||||
|
|
|
@ -109,4 +109,25 @@ export const fetchTaxonomyTerms = ({ commit }, taxonomyId) => {
|
||||||
})
|
})
|
||||||
.catch(error => reject(error));
|
.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));
|
||||||
|
});
|
||||||
};
|
};
|
|
@ -22,6 +22,10 @@ export const getTaxonomyTerms = state => {
|
||||||
return state.taxonomyTerms;
|
return state.taxonomyTerms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getActivities = state => {
|
||||||
|
return state.activities;
|
||||||
|
};
|
||||||
|
|
||||||
export const getStackedBarChartOptions = state => {
|
export const getStackedBarChartOptions = state => {
|
||||||
return state.stackedBarChartOptions;
|
return state.stackedBarChartOptions;
|
||||||
};
|
};
|
||||||
|
@ -33,3 +37,7 @@ export const getHorizontalBarChartOptions = state => {
|
||||||
export const getDonutChartOptions = state => {
|
export const getDonutChartOptions = state => {
|
||||||
return state.donutChartOptions;
|
return state.donutChartOptions;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getHeatMapChartOptions = state => {
|
||||||
|
return state.heatMapChartOptions;
|
||||||
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ const state = {
|
||||||
taxonomyTerms: {},
|
taxonomyTerms: {},
|
||||||
metadata: {},
|
metadata: {},
|
||||||
metadataList: {},
|
metadataList: {},
|
||||||
|
activities: {},
|
||||||
stackedBarChartOptions: {
|
stackedBarChartOptions: {
|
||||||
chart: {
|
chart: {
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
|
@ -132,6 +133,18 @@ const state = {
|
||||||
horizontalAlign: 'left',
|
horizontalAlign: 'left',
|
||||||
offsetX: 40,
|
offsetX: 40,
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
heatMapChartOptions: {
|
||||||
|
chart: {
|
||||||
|
height: 350,
|
||||||
|
type: 'heatmap',
|
||||||
|
},
|
||||||
|
dataLabels: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: ''
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ export const setTaxonomyTerms = (state, taxonomyTerms) => {
|
||||||
state.taxonomyTerms = taxonomyTerms;
|
state.taxonomyTerms = taxonomyTerms;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const setActivities = (state, activities) => {
|
||||||
|
state.activities = activities;
|
||||||
|
};
|
||||||
|
|
||||||
export const setStackedBarChartOptions = (state, stackedBarChartOptions) => {
|
export const setStackedBarChartOptions = (state, stackedBarChartOptions) => {
|
||||||
state.stackedBarChartOptions = stackedBarChartOptions;
|
state.stackedBarChartOptions = stackedBarChartOptions;
|
||||||
};
|
};
|
||||||
|
@ -32,4 +36,8 @@ export const setHorizontalBarChartOptions = (state, horizontalBarChartOptions) =
|
||||||
|
|
||||||
export const setDonutChartOptions = (state, donutChartOptions) => {
|
export const setDonutChartOptions = (state, donutChartOptions) => {
|
||||||
state.donutChartOptions = donutChartOptions;
|
state.donutChartOptions = donutChartOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setHeatMapChartOptions = (state, heatMapChartOptions) => {
|
||||||
|
state.heatMapChartOptions = heatMapChartOptions;
|
||||||
};
|
};
|
|
@ -170,6 +170,21 @@
|
||||||
style="min-height=380px"
|
style="min-height=380px"
|
||||||
class="skeleton postbox" />
|
class="skeleton postbox" />
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="activities != undefined"
|
||||||
|
class="column is-full">
|
||||||
|
<apexchart
|
||||||
|
v-if="!isFetchingActivities"
|
||||||
|
height="380px"
|
||||||
|
class="postbox"
|
||||||
|
type="heatmap"
|
||||||
|
:series="activitiesChartSeries"
|
||||||
|
:options="activitiesChartOptions" />
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
style="min-height=380px"
|
||||||
|
class="skeleton postbox" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -191,6 +206,7 @@ export default {
|
||||||
isFetchingTaxonomyTerms: false,
|
isFetchingTaxonomyTerms: false,
|
||||||
isFetchingMetadata: false,
|
isFetchingMetadata: false,
|
||||||
isFetchingMetadataList: false,
|
isFetchingMetadataList: false,
|
||||||
|
isFetchingActivities: false,
|
||||||
collectionsListChartSeries: [],
|
collectionsListChartSeries: [],
|
||||||
collectionsListChartOptions: {},
|
collectionsListChartOptions: {},
|
||||||
taxonomiesListChartSeries: [],
|
taxonomiesListChartSeries: [],
|
||||||
|
@ -203,7 +219,9 @@ export default {
|
||||||
metadataTypeChartOptions: {},
|
metadataTypeChartOptions: {},
|
||||||
metadataDistributionChartSeries: [],
|
metadataDistributionChartSeries: [],
|
||||||
metadataDistributionChartOptions: {},
|
metadataDistributionChartOptions: {},
|
||||||
metadataDistributionChartHeight: 730
|
metadataDistributionChartHeight: 730,
|
||||||
|
activitiesChartSeries: [],
|
||||||
|
activitiesChartOptions: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -217,9 +235,11 @@ export default {
|
||||||
taxonomyTerms: 'getTaxonomyTerms',
|
taxonomyTerms: 'getTaxonomyTerms',
|
||||||
taxonomiesList: 'getTaxonomiesList',
|
taxonomiesList: 'getTaxonomiesList',
|
||||||
collectionsList: 'getCollectionsList',
|
collectionsList: 'getCollectionsList',
|
||||||
|
activities: 'getActivities',
|
||||||
stackedBarChartOptions: 'getStackedBarChartOptions',
|
stackedBarChartOptions: 'getStackedBarChartOptions',
|
||||||
donutChartOptions: 'getDonutChartOptions',
|
donutChartOptions: 'getDonutChartOptions',
|
||||||
horizontalBarChartOptions: 'getHorizontalBarChartOptions'
|
horizontalBarChartOptions: 'getHorizontalBarChartOptions',
|
||||||
|
heatMapChartOptions: 'getHeatMapChartOptions'
|
||||||
}),
|
}),
|
||||||
taxonomiesListArray() {
|
taxonomiesListArray() {
|
||||||
return this.taxonomiesList && this.taxonomiesList != undefined ? Object.values(this.taxonomiesList) : [];
|
return this.taxonomiesList && this.taxonomiesList != undefined ? Object.values(this.taxonomiesList) : [];
|
||||||
|
@ -234,6 +254,7 @@ export default {
|
||||||
this.selectedCollection = to['collection'] ? to['collection'] : 'default';
|
this.selectedCollection = to['collection'] ? to['collection'] : 'default';
|
||||||
this.loadSummary();
|
this.loadSummary();
|
||||||
this.loadMetadata();
|
this.loadMetadata();
|
||||||
|
this.loadActivities();
|
||||||
|
|
||||||
if (!this.selectedCollection || this.selectedCollection == 'default') {
|
if (!this.selectedCollection || this.selectedCollection == 'default') {
|
||||||
this.loadCollectionsList();
|
this.loadCollectionsList();
|
||||||
|
@ -269,7 +290,8 @@ export default {
|
||||||
'fetchTaxonomiesList',
|
'fetchTaxonomiesList',
|
||||||
'fetchTaxonomyTerms',
|
'fetchTaxonomyTerms',
|
||||||
'fetchMetadata',
|
'fetchMetadata',
|
||||||
'fetchMetadataList'
|
'fetchMetadataList',
|
||||||
|
'fetchActivities'
|
||||||
]),
|
]),
|
||||||
loadCollections() {
|
loadCollections() {
|
||||||
this.isFetchingCollections = true;
|
this.isFetchingCollections = true;
|
||||||
|
@ -578,6 +600,97 @@ export default {
|
||||||
this.isFetchingMetadataList = false;
|
this.isFetchingMetadataList = false;
|
||||||
})
|
})
|
||||||
.catch(() => 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue