11<template >
2- <Bar :data =" data" :options =" options" v-if =" isLoaded" />
2+ <p class =" description" >{{ t('intervalChartChart.description') }}</p >
3+ <div ref =" chart" id =" timeIntervalChartD3" ></div >
34</template >
45
56<script lang="ts">
@@ -9,22 +10,175 @@ export default {
910 </script >
1011
1112<script lang="ts" setup>
12- import { Bar } from ' vue-chartjs' ;
13- import {
14- Chart as ChartJS ,
15- Title ,
16- Tooltip ,
17- Legend ,
18- BarElement ,
19- LinearScale ,
20- CategoryScale ,
21- } from ' chart.js' ;
2213import { onMounted , ref } from ' vue' ;
2314import { injecStorage } from ' ../storage/inject-storage' ;
2415import { StorageDeserializeParam } from ' ../storage/storage-params' ;
2516import { TimeInterval } from ' ../entity/time-interval' ;
2617import { todayLocalDate } from ' ../utils/date' ;
18+ import { useI18n } from ' vue-i18n' ;
2719import { convertHoursToTime , convertStringTimeIntervalToSeconds } from ' ../utils/converter' ;
20+ import * as d3 from ' d3' ;
21+
22+ const { t } = useI18n ();
23+
24+ const chart = ref <any >();
25+
26+ onMounted (async () => {
27+ const timeIntervalList = (await storage .getDeserializeList (
28+ StorageDeserializeParam .TIMEINTERVAL_LIST ,
29+ )) as TimeInterval [];
30+
31+ // data.intervals.forEach(function (interval) {
32+ // resultArr.push({ domain: data.domain, interval: interval });
33+ // });
34+ const data = [
35+ {
36+ domain: ' google.com' ,
37+ interval: ' 10:12:18-10:25:17' ,
38+ },
39+ {
40+ domain: ' habr.com' ,
41+ interval: ' 10:28:18-10:31:17' ,
42+ },
43+ {
44+ domain: ' medium.com' ,
45+ interval: ' 11:41:18-11:48:17' ,
46+ },
47+ {
48+ domain: ' xy.com' ,
49+ interval: ' 02:41:18-03:01:17' ,
50+ },
51+ ];
52+ drawIntervalChart (data );
53+ });
54+
55+ function drawIntervalChart(data ) {
56+ data .forEach (function (item ) {
57+ var hFrom = getHourFrom (item .interval );
58+ var hTo = getHourTo (item .interval );
59+ if (hFrom != hTo ) {
60+ var sourceTimeFrom = item .interval .split (' -' )[0 ].split (' :' );
61+ var sourceTimeTo = item .interval .split (' -' )[1 ].split (' :' );
62+ var timeTo = ` ${sourceTimeFrom [0 ]}:59:59 ` ;
63+ var timeFrom = ` ${sourceTimeTo [0 ]}:00:00 ` ;
64+ data .push ({ domain: item .domain , interval: item .interval .split (' -' )[0 ] + ' -' + timeTo });
65+ data .push ({ domain: item .domain , interval: timeFrom + ' -' + item .interval .split (' -' )[1 ] });
66+ }
67+ });
68+
69+ const margin = { top: 10 , right: 10 , bottom: 20 , left: 20 };
70+ const width = chart .value .offsetWidth ;
71+ const height = 400 ;
72+
73+ const tickDistance = 4.38 ;
74+
75+ const tooltip = d3
76+ .select (' #timeIntervalChartD3' )
77+ .append (' div' )
78+ .style (' opacity' , 0 )
79+ .style (' display' , ' none' )
80+ .style (' position' , ' absolute' )
81+ .style (' background-color' , ' white' )
82+ .style (' color' , ' black' )
83+ .style (' border' , ' 1px solid grey' )
84+ .attr (' class' , ' tooltip' )
85+ .style (' border-width' , ' 1px' )
86+ .style (' border-radius' , ' 3px' )
87+ .style (' padding' , ' 5px' );
88+
89+ const mouseover = function (e : any ) {
90+ tooltip .style (' opacity' , 1 ).style (' display' , ' block' );
91+ d3 .select (' .tooltip' )
92+ .style (' left' , e .layerX + 15 + ' px' )
93+ .style (' top' , e .layerY + 15 + ' px' );
94+ };
95+ const mousemove = function (event : any , data : any ) {
96+ tooltip .html (` <b>${data .domain }</b><br>${data .interval } ` );
97+ };
98+ const mouseleave = function (e : any ) {
99+ tooltip .style (' opacity' , 0 ).style (' display' , ' none' );
100+ };
101+
102+ // create the svg
103+ const svg = d3
104+ .select (' #timeIntervalChartD3' )
105+ .append (' svg' )
106+ .attr (' width' , width + margin .left + margin .right )
107+ .attr (' height' , height + margin .top + margin .bottom )
108+ .append (' g' )
109+ .attr (' transform' , ` translate(${margin .left },${margin .top }) ` );
110+
111+ const y = d3 .scaleLinear ([height , 0 ]).domain ([0 , 60 ]);
112+ const yAxis = d3 .axisLeft (y );
113+
114+ const x = d3 .scaleLinear ([0 , width ]).domain ([0 , 24 ]);
115+ const xAxis = d3 .axisBottom (x ).ticks (24 );
116+
117+ svg
118+ .append (' g' )
119+ .attr (' class' , ' grid' )
120+ .style (' color' , ' #e5e5e5' )
121+ .attr (' transform' , ` translate(0, ${height }) ` )
122+ .call (xAxis .tickSize (- height ));
123+
124+ svg .append (' g' ).attr (' class' , ' grid' ).style (' color' , ' #e5e5e5' ).call (yAxis .tickSize (- width ));
125+ svg .selectAll (' text' ).style (' fill' , ' black' );
126+
127+ // draw the bars, offset y and bar height based on data
128+ svg
129+ .selectAll (' .bar' )
130+ .data (data )
131+ .enter ()
132+ .append (' rect' )
133+ .style (' fill' , ' #5668e2' )
134+ .style (' cursor' , ' pointer' )
135+ .style (' stroke-width' , ' 1' )
136+ .attr (' class' , ' bar' )
137+ .attr (' x' , (data : any ) => x (getHourFrom (data .interval )) + 2 )
138+ .attr (' width' , 25 )
139+ .attr (' y' , (data : any ) => y (getMinutesTo (data .interval )) - 1 )
140+ .attr (' height' , (data : any ) => {
141+ const offset = getMinutesTo (data .interval ) - getMinutesFrom (data .interval );
142+ if (offset == 0 ) {
143+ const offsetSeconds = getSecondsTo (data .interval ) - getSecondsFrom (data .interval );
144+ if (offsetSeconds <= 3 ) return 0 ;
145+ else return 1 ;
146+ } else return offset * tickDistance ;
147+ })
148+ .on (' mouseover' , mouseover )
149+ .on (' mousemove' , mousemove )
150+ .on (' mouseleave' , mouseleave );
151+
152+ function getHourFrom(interval : string ): number {
153+ const time = interval .split (' -' )[0 ];
154+ return Number (time .split (' :' )[0 ]);
155+ }
156+
157+ function getHourTo(interval : string ): number {
158+ var time = interval .split (' -' )[1 ];
159+ return Number (time .split (' :' )[0 ]);
160+ }
161+
162+ function getMinutesFrom(interval : string ): number {
163+ var time = interval .split (' -' )[0 ];
164+ return Number (time .split (' :' )[1 ]);
165+ }
166+
167+ function getMinutesTo(interval : string ): number {
168+ var time = interval .split (' -' )[1 ];
169+ return Number (time .split (' :' )[1 ]);
170+ }
171+
172+ function getSecondsFrom(interval : string ): number {
173+ var time = interval .split (' -' )[0 ];
174+ return Number (time .split (' :' )[2 ]);
175+ }
176+
177+ function getSecondsTo(interval : string ): number {
178+ var time = interval .split (' -' )[1 ];
179+ return Number (time .split (' :' )[2 ]);
180+ }
181+ }
28182
29183type DataForChart = {
30184 summary: number ;
@@ -40,8 +194,6 @@ type DomainsInterval = {
40194
41195const storage = injecStorage ();
42196
43- ChartJS .register (CategoryScale , LinearScale , BarElement , Title , Tooltip , Legend );
44-
45197const options = ref <any >();
46198const data = ref <any >();
47199const isLoaded = ref <boolean >();
@@ -164,46 +316,24 @@ async function buildChart() {
164316 minutes .push (index );
165317 }
166318
167- const dataForChart = fillData (timeIntervalList );
168- data .value = {
169- labels: hours ,
170- datasets: dataForChart ,
171- };
172-
173- options .value = {
174- responsive: true ,
175- maintainAspectRatio: false ,
176- plugins: {
177- legend: {
178- position: ' none' ,
179- },
180- tooltip: {
181- callbacks: {
182- label : function (context : any ) {
183- return ` ${context .label }:00-${Number (context .label ) + 1 }:00 ${convertHoursToTime (
184- context .raw ,
185- )} ` ;
186- },
187- },
188- },
189- },
190- scales: {
191- y: {
192- min: 0 ,
193- max: 60 ,
194- ticks: {
195- stepSize: 5 ,
196- },
197- },
198- x: {
199- stacked: true ,
200- min: 0 ,
201- max: 23 ,
202- },
203- },
204- };
205319 isLoaded .value = true ;
206320}
207321
208322onMounted (async () => await buildChart ());
209323 </script >
324+
325+ <style scoped>
326+ .block {
327+ display : inline-block ;
328+ border : 1px rgb (197 , 197 , 197 ) solid ;
329+ background-color : white ;
330+ height : 40px ;
331+ width : 40px ;
332+ }
333+
334+ .grid line {
335+ stroke : gray ;
336+ stroke-opacity : 0.2 ;
337+ color : black ;
338+ }
339+ </style >
0 commit comments