1 | <?php |
||
2 | |||
3 | /** @noinspection PhpDocMissingThrowsInspection */ |
||
4 | |||
5 | require_once 'vendor/autoload.php'; |
||
6 | |||
7 | use Vctls\IntervalGraph\IntervalGraph; |
||
8 | use Vctls\IntervalGraph\Util\Date as D; |
||
9 | |||
10 | $today = new DateTime('today'); |
||
11 | |||
12 | $base = D::intv(0, 5); |
||
13 | $intv1 = D::intv(0, 4, 7 / 10); |
||
14 | $intv2 = D::intv(1, 5, 3 / 10); |
||
15 | $intv3 = D::intv(2, 3, 3 / 10); |
||
16 | $overlapped1 = D::intvg([$base, $intv1]); |
||
17 | $overlapped2 = D::intvg([$base, $intv2]); |
||
18 | $overlapped3 = D::intvg([$base, $intv3]); |
||
19 | $overlapped = D::intvg([$base, $intv1, $intv2, $intv3]); |
||
20 | |||
21 | $withNull1 = D::intvg([$base, D::intv(0, 3, 4 / 10)]); |
||
22 | $withNull2 = D::intvg([$base, D::intv(1, 2)]); |
||
23 | $withNull3 = D::intvg([$base, D::intv(2, 3, 4 / 10)]); |
||
24 | $withNull4 = D::intvg([$base, D::intv(4, 5, 5 / 10)]); |
||
25 | $withNullIntervals = D::intvg([ |
||
26 | D::intv(0, 3, 4 / 10), |
||
27 | D::intv(1, 2), |
||
28 | D::intv(2, 3, 4 / 10), |
||
29 | D::intv(4, 5, 5 / 10), |
||
30 | ]); |
||
31 | |||
32 | $longIntervals = [ |
||
33 | [$today, new DateTime('today + 3 days'), 2 / 10], |
||
34 | D::intv(1, 4, 2 / 10), |
||
35 | D::intv(2, 5, 3 / 10), |
||
36 | D::intv(3, 6, 5 / 10), |
||
37 | D::intv(4, 7, 4 / 10), |
||
38 | D::intv(5, 8, 2 / 10), |
||
39 | D::intv(6, 9, 2 / 10), |
||
40 | ]; |
||
41 | |||
42 | $longDateFormat = function (DateTime $bound) { |
||
43 | return $bound->format('Y-m-d H:i:s'); |
||
44 | }; |
||
45 | |||
46 | $long = (D::intvg($longIntervals))->setBoundToString($longDateFormat); |
||
47 | |||
48 | /* |
||
49 | * CUSTOM VALUE TYPES |
||
50 | */ |
||
51 | |||
52 | // An aggregate function for arrays representing fractions with the same denominator. |
||
53 | $agg = function ($a, $b) { |
||
54 | if ($a === null && $b === null) return null; |
||
55 | return [$a[0] + $b[0], $b[1]]; |
||
56 | }; |
||
57 | |||
58 | // A toNumeric function… |
||
59 | $toNumeric = function ($a) { |
||
60 | return $a === null ? null : (int)($a[0] / $a[1] * 100); |
||
61 | }; |
||
62 | |||
63 | // A toString function… |
||
64 | $toString = function ($a) { |
||
65 | return $a === null ? null : ($a[0] . '/' . $a[1]); |
||
66 | }; |
||
67 | |||
68 | $fractions = [ |
||
69 | D::intv(1, 4, [2, 10]), |
||
70 | D::intv(2, 5, [3, 10]), |
||
71 | D::intv(3, 6, [5, 10]), |
||
72 | D::intv(4, 7, [4, 10]), |
||
73 | D::intv(5, 8, [2, 10]), |
||
74 | D::intv(6, 9, [2, 10]), |
||
75 | ]; |
||
76 | $fractim = (D::intvg($fractions)) |
||
77 | ->setAggregate($agg) |
||
78 | ->setValueToNumeric($toNumeric) |
||
79 | ->setValueToString($toString); |
||
80 | $fract = $fractim->draw(); |
||
81 | |||
82 | /* /CUSTOM VALUE TYPES */ |
||
83 | |||
84 | /* |
||
85 | * TRUNCATED INTERVALS |
||
86 | */ |
||
87 | try { |
||
88 | $intv1 = (clone $today)->add(new DateInterval('PT60H')); |
||
89 | $intv2 = (clone $today)->add(new DateInterval('PT108H')); |
||
90 | $intv3 = (clone $intv2)->add(new DateInterval('PT60H')); |
||
91 | } catch (Exception $e) { |
||
0 ignored issues
–
show
Coding Style
Comprehensibility
introduced
by
![]() |
|||
92 | } |
||
93 | |||
94 | $truncated = ($fractim->setIntervals(IntervalGraph::truncate($fractions, $intv1, $intv2))) |
||
95 | ->setBoundToString($longDateFormat); |
||
96 | /* /TRUNCATED INTERVALS */ |
||
97 | |||
98 | $withDates = (D::intvg([ |
||
99 | [$intv1, $intv1], |
||
100 | D::intv(0, 4, 7 / 10), |
||
101 | [$intv2, $intv2], |
||
102 | D::intv(1, 5, 3 / 10), |
||
103 | D::intv(2, 3, 3 / 10), |
||
104 | [$intv3, $intv3], |
||
105 | ])) |
||
106 | ->setBoundToString($longDateFormat);; |
||
107 | |||
108 | $intvGraphs = []; |
||
109 | foreach (range(0, 20) as $t) { |
||
110 | $intervals = []; |
||
111 | $j = (int)rand(3, 6); |
||
112 | for ($i = 0; $i < $j; $i++) { |
||
113 | $intervals[] = [D::rdm(), D::rdm(), rand(1, 9) / 10]; |
||
114 | } |
||
115 | $intvGraphs[] = (D::intvg($intervals))->checkIntervals(); |
||
116 | } |
||
117 | |||
118 | |||
119 | ?> |
||
120 | <!doctype html> |
||
121 | <html lang="en"> |
||
122 | <head> |
||
123 | <title>Php IntervalGraph demo</title> |
||
124 | <link rel="stylesheet" href="styles.css"> |
||
125 | <script type="application/javascript" src="app.js"></script> |
||
126 | </head> |
||
127 | <body style="font-family: sans-serif;"> |
||
128 | <header> |
||
129 | <h1>PHP Interval Graph demo</h1> |
||
130 | </header> |
||
131 | <p> |
||
132 | PHP Interval Graph is a small utility to manipulate and |
||
133 | display arrays of intervals. |
||
134 | </p> |
||
135 | <a href="https://github.com/vctls/php-interval-graph"> |
||
136 | https://github.com/vctls/php-interval-graph |
||
137 | </a> |
||
138 | <h2>How it works</h2> |
||
139 | <p> |
||
140 | Here are three overlapping date intervals. |
||
141 | Each one has a linked rate, displayed as a percentage when hovering it. |
||
142 | <br>They are all displayed over the same period of time, which has no rate. |
||
143 | </p> |
||
144 | <div style="margin-bottom: 2px"><?= $overlapped1 ?></div> |
||
145 | <div style="margin-bottom: 2px"><?= $overlapped2 ?></div> |
||
146 | <div style="margin-bottom: 2px"><?= $overlapped3 ?></div> |
||
147 | |||
148 | <p> |
||
149 | Gathered on the same graph, they are displayed as follows. |
||
150 | </p> |
||
151 | <?= $overlapped ?> |
||
152 | |||
153 | <h2>More examples</h2> |
||
154 | <p> |
||
155 | Overlapping intervals with a couple null intervals.<br> |
||
156 | The first null interval overlaps a non null one. |
||
157 | This cuts the non null interval, while the weight remains the same.<br> |
||
158 | The second null interval is implicit. |
||
159 | It is simply the gap between the two last intervals. |
||
160 | </p> |
||
161 | <div style="margin-bottom: 2px"><?= $withNull1 ?></div> |
||
162 | <div style="margin-bottom: 2px"><?= $withNull2 ?></div> |
||
163 | <div style="margin-bottom: 2px"><?= $withNull3 ?></div> |
||
164 | <div style="margin-bottom: 2px"><?= $withNull4 ?></div> |
||
165 | <br> |
||
166 | <?= $withNullIntervals ?> |
||
167 | |||
168 | |||
169 | <h2>Custom value types</h2> |
||
170 | <p> |
||
171 | The following graph takes arrays of two values |
||
172 | and displays them as fractions.<br> |
||
173 | In order to use custom value types, you need to set the custom functions |
||
174 | that will aggregate the values, convert them to numeric values and strings. |
||
175 | </p> |
||
176 | <?= $fract ?> |
||
177 | |||
178 | <p> |
||
179 | The same graph, truncated between <?= $intv1->format('Y-m-d H:i:s') ?> |
||
180 | and <?= $intv2->format('Y-m-d H:i:s') ?>. |
||
181 | <?= $truncated ?> |
||
182 | </p> |
||
183 | |||
184 | <p> |
||
185 | A graph with three isolated dates, shown as black bars. |
||
186 | <br>One of the dates goes beyond all intervals. |
||
187 | <?= $withDates ?> |
||
188 | </p> |
||
189 | |||
190 | <?php |
||
191 | |||
192 | /* ADDITIONAL INFORMATION */ |
||
193 | $toString2 = function ($a) { |
||
194 | if ($a === null) { |
||
195 | return null; |
||
196 | } |
||
197 | return $a[0] . '/' . $a[1] . ($a[2] ? '*' : ''); |
||
198 | }; |
||
199 | |||
200 | $agg2 = function ($a, $b) { |
||
201 | if ($a === null && $b === null) return null; |
||
202 | return [ |
||
203 | $a[0] + $b[0], |
||
204 | $b[1], |
||
205 | $a[2] || $b[2] |
||
206 | ]; |
||
207 | }; |
||
208 | |||
209 | $addInfo = D::intvg([ |
||
210 | D::intv(0, 3), |
||
211 | D::intv(0, 2, [1, 3, false]), |
||
212 | D::intv(1, 3, [2, 5, true]), |
||
213 | ]) |
||
214 | ->setValueToString($toString2) |
||
215 | ->setValueToNumeric($toNumeric) |
||
216 | ->setAggregate($agg2); |
||
217 | ?> |
||
218 | |||
219 | <h2>Passing additional information</h2> |
||
220 | <p> |
||
221 | You can take advantage of the closures and templates to display additional information on the graph. |
||
222 | Here for example, interval values hold a boolean. Depending on the boolean, an asterisk is added to the string, |
||
223 | and a class is set on the corresponding bars. |
||
224 | <?= $addInfo ?> |
||
225 | </p> |
||
226 | |||
227 | <p> |
||
228 | A bunch of random graphs, this time generated through JavaScript: |
||
229 | <br> |
||
230 | </p> |
||
231 | <div id="random"></div> |
||
232 | <script> |
||
233 | 'use strict'; |
||
234 | const graphs = JSON.parse('<?= json_encode($intvGraphs) ?>'); |
||
235 | const el = document.getElementById('random'); |
||
236 | |||
237 | try { |
||
238 | graphs.forEach(function (graph) { |
||
239 | let html = document.createRange().createContextualFragment(intvg(graph)); |
||
240 | el.appendChild(html); |
||
241 | }); |
||
242 | } catch (e) { |
||
243 | el.innerHTML = 'The JavaScript function uses ES6 string literals. Sorry not sorry, IE.'; |
||
244 | } |
||
245 | </script> |
||
246 | </body> |
||
247 | </html> |