Skip to content

Commit 86c116f

Browse files
committed
Time chart by hours
1 parent b6a649e commit 86c116f

File tree

8 files changed

+235
-5
lines changed

8 files changed

+235
-5
lines changed

src/_locales/de/messages.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
"message": "Im letzten Monat"
115115
},
116116
"generalSettings": {
117-
"message": "Grundlegende Einstellungen"
117+
"message": "Einstellungen"
118118
},
119119
"whiteListSettings": {
120120
"message": "Weiße Liste"
@@ -225,5 +225,11 @@
225225
},
226226
"mostVisited": {
227227
"message": "Die meistbesuchte Website "
228+
},
229+
"timeChart": {
230+
"message": "Die heutige Zeit"
231+
},
232+
"timeChartDescription": {
233+
"message": "Dies ist eine stundenweise Zeitleiste für den Tag"
228234
}
229235
}

src/_locales/en/messages.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
"message": "Last month"
115115
},
116116
"generalSettings": {
117-
"message": "General Settings"
117+
"message": "Settings"
118118
},
119119
"whiteListSettings": {
120120
"message": "WhiteList"
@@ -225,5 +225,11 @@
225225
},
226226
"mostVisited": {
227227
"message": "Most visited website "
228+
},
229+
"timeChart": {
230+
"message": "Today's time"
231+
},
232+
"timeChartDescription": {
233+
"message": "This is a chart of time during the day by the hour"
228234
}
229235
}

src/_locales/ru/messages.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
"message": "Последний месяц"
115115
},
116116
"generalSettings": {
117-
"message": "Основные настройки"
117+
"message": "Настройки"
118118
},
119119
"whiteListSettings": {
120120
"message": "Белый список"
@@ -225,5 +225,11 @@
225225
},
226226
"mostVisited": {
227227
"message": "Самый посещаемый сайт "
228+
},
229+
"timeChart": {
230+
"message": "Время сегодня"
231+
},
232+
"timeChartDescription": {
233+
"message": "Это график времени в течение дня по часам"
228234
}
229235
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
<template>
2+
<div class="settings-item">
3+
<label class="setting-header"> {{ t('timeChart.message') }} </label>
4+
<p class="description">{{ t('timeChartDescription.message') }}</p>
5+
</div>
6+
<div class="chart">
7+
<Bar :data="data" :options="options" v-if="isLoaded" />
8+
</div>
9+
</template>
10+
11+
<script lang="ts">
12+
export default {
13+
name: 'TimeIntervalChart',
14+
};
15+
</script>
16+
17+
<script lang="ts" setup>
18+
import { Bar } from 'vue-chartjs';
19+
import { useI18n } from 'vue-i18n';
20+
import {
21+
Chart as ChartJS,
22+
Title,
23+
Tooltip,
24+
Legend,
25+
BarElement,
26+
LinearScale,
27+
CategoryScale,
28+
} from 'chart.js';
29+
import { onMounted, ref } from 'vue';
30+
import { injecStorage } from '../storage/inject-storage';
31+
import { StorageDeserializeParam } from '../storage/storage-params';
32+
import { TimeInterval } from '../entity/time-interval';
33+
import { todayLocalDate } from '../utils/date';
34+
import { convertHoursToTime, convertStringTimeIntervalToSeconds } from '../utils/converter';
35+
36+
const { t } = useI18n();
37+
38+
type DataForChart = {
39+
summary: number;
40+
hour: number;
41+
domains: DomainsInterval[];
42+
};
43+
44+
type DomainsInterval = {
45+
hour: number;
46+
summary: number;
47+
domain: string;
48+
};
49+
50+
const storage = injecStorage();
51+
52+
ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend);
53+
54+
const options = ref<any>();
55+
const data = ref<any>();
56+
const isLoaded = ref<boolean>();
57+
58+
const objects: DataForChart[] = [];
59+
const hours: number[] = [];
60+
61+
isLoaded.value = false;
62+
63+
function convertTimIntervalToObject(timeInterval: string, domain: string): DomainsInterval | null {
64+
const array = timeInterval.split('-');
65+
const time1 = array[0].split(':');
66+
const time2 = array[1].split(':');
67+
//добавить подсчет, если в разных часах интервал
68+
if (time1[0] == time2[0]) {
69+
return {
70+
hour: Number(time1[0]),
71+
summary:
72+
convertStringTimeIntervalToSeconds(array[1]) - convertStringTimeIntervalToSeconds(array[0]),
73+
domain: domain,
74+
};
75+
}
76+
return null;
77+
}
78+
79+
function fillData(timeIntervalList: TimeInterval[]) {
80+
const items = timeIntervalList?.filter(x => x.day == todayLocalDate());
81+
const domains = items.map(x => x.domain);
82+
const result: any[] = [];
83+
const intervalsObj: DomainsInterval[] = [];
84+
domains.forEach(domain => {
85+
const intervals = items.filter(x => x.domain == domain);
86+
intervals.forEach(array => {
87+
const i = array.intervals;
88+
i.forEach(time => {
89+
const obj = convertTimIntervalToObject(time, domain);
90+
if (obj != null) {
91+
const existDomain = intervalsObj.find(x => x.domain == domain && x.hour == obj.hour);
92+
if (existDomain != undefined) {
93+
existDomain.summary += obj.summary;
94+
} else intervalsObj.push(obj);
95+
}
96+
});
97+
});
98+
});
99+
100+
const tempArray: number[] = [];
101+
for (let index = 0; index < 24; index++) {
102+
const obj = objects.find(x => x.hour == index);
103+
const intervalObj = intervalsObj.filter(x => x.hour == index);
104+
const summary =
105+
intervalObj.length == 0 ? 0 : intervalObj.map(x => x.summary).reduce((a, b) => a + b);
106+
if (obj == undefined) {
107+
const newObj = {
108+
summary: summary,
109+
hour: index,
110+
domains: intervalObj,
111+
};
112+
objects.push(newObj);
113+
} else {
114+
obj.summary += summary;
115+
intervalObj.forEach(element => {
116+
obj.domains.push(element);
117+
});
118+
}
119+
120+
tempArray.push(0);
121+
}
122+
123+
objects.forEach(obj => {
124+
const emptyArray: number[] = Object.assign([], tempArray);
125+
emptyArray[obj.hour] = Number((obj.summary / 60).toFixed(4));
126+
result.push({
127+
backgroundColor: ['#5668e2'],
128+
data: emptyArray,
129+
});
130+
});
131+
132+
return result;
133+
}
134+
135+
async function buildChart() {
136+
const timeIntervalList = (await storage.getDeserializeList(
137+
StorageDeserializeParam.TIMEINTERVAL_LIST,
138+
)) as TimeInterval[];
139+
for (let index = 0; index <= 23; index++) {
140+
hours.push(index);
141+
}
142+
let minutes: number[] = [];
143+
for (let index = 1; index < 60; index++) {
144+
minutes.push(index);
145+
}
146+
147+
const dataForChart = fillData(timeIntervalList);
148+
data.value = {
149+
labels: hours,
150+
datasets: dataForChart,
151+
};
152+
153+
options.value = {
154+
responsive: true,
155+
maintainAspectRatio: false,
156+
plugins: {
157+
legend: {
158+
position: 'none',
159+
},
160+
tooltip: {
161+
callbacks: {
162+
label: function (context: any) {
163+
return `${context.label}:00-${Number(context.label) + 1}:00 ${convertHoursToTime(
164+
context.raw,
165+
)}`;
166+
},
167+
},
168+
},
169+
},
170+
scales: {
171+
y: {
172+
min: 0,
173+
max: 60,
174+
ticks: {
175+
stepSize: 5,
176+
},
177+
},
178+
x: {
179+
stacked: true,
180+
min: 0,
181+
max: 23,
182+
},
183+
},
184+
};
185+
isLoaded.value = true;
186+
}
187+
188+
onMounted(async () => await buildChart());
189+
</script>
190+
191+
<style scoped>
192+
.chart {
193+
height: 350px;
194+
margin: auto;
195+
width: 80%;
196+
margin: 20px;
197+
}
198+
</style>

src/pages/Dashboard.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
checked
1515
v-on:change="selectTab(SettingsTab.TimeIntervalChart)"
1616
/>
17-
<label name="tabName" for="timeIntervalChart-tab">Today Time chart</label>
17+
<label name="tabName" for="timeIntervalChart-tab">{{ t('timeChart.message') }}</label>
1818

1919
<div class="settings-content">
2020
<TimeIntervalChart v-if="selectedTab == SettingsTab.TimeIntervalChart" />

src/utils/converter.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import i18n, { getMessagesFromLocale } from '../plugins/i18n';
2-
import { HOUR, MINUTE, Time } from './time';
2+
import { HOUR, HOUR_IN_SECONDS, MINUTE, MINUTE_IN_SECONDS, Time } from './time';
33

44
export function convertHHMMToSeconds(hours: number, minutes: number) {
55
return hours * 3600 + minutes * 60;
@@ -82,3 +82,13 @@ function zeroAppend(time: number) {
8282
if (time < 10) return `0${time}`;
8383
else return time;
8484
}
85+
86+
export function convertStringTimeIntervalToSeconds(timeInterval: string) {
87+
const time = timeInterval.split(':');
88+
return Number(time[0]) * HOUR_IN_SECONDS + Number(time[1]) * MINUTE_IN_SECONDS + Number(time[2]);
89+
}
90+
91+
export function convertHoursToTime(time: number) {
92+
const timeInSeconds = Math.floor(time * MINUTE_IN_SECONDS);
93+
return convertSummaryTimeToString(timeInSeconds);
94+
}

src/utils/enums.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export enum SortingBy {
1010
}
1111

1212
export enum SettingsTab {
13+
TimeIntervalChart,
1314
GeneralSettings,
1415
WhiteList,
1516
Limits,

src/utils/time.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ export type Time = {
55
minutes: number;
66
};
77

8+
export const MINUTE_IN_SECONDS = 60;
9+
export const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
10+
811
//Every day - 60 minutes * 24 hours
912
export const DAY_MINUTES = 1440;
1013
export const SECOND = 1000;

0 commit comments

Comments
 (0)