Completed
Push — master ( d228f2...cb5f1c )
by Victor
07:17
created
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
Consider adding a comment why this CATCH block is empty.
Loading history...
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>