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