1<?php 2 3// phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps 4namespace dokuwiki\plugin\statistics; 5 6/** 7 * Create the data for graph visualization 8 */ 9class StatisticsGraph 10{ 11 private \helper_plugin_statistics $hlp; 12 private string $from; 13 private string $to; 14 private int $width; 15 private int $height; 16 17 /** 18 * Initialize a new Graph 19 * 20 * @param \helper_plugin_statistics $hlp 21 * @param string $from From date 22 * @param string $to To date 23 * @param int $width width of the graph in pixels 24 * @param int $height height of the graph in pixels 25 */ 26 public function __construct(\helper_plugin_statistics $hlp, $from, $to, $width, $height) 27 { 28 $this->hlp = $hlp; 29 $this->from = $from; 30 $this->to = $to; 31 $this->width = $width; 32 $this->height = $height; 33 } 34 35 /** 36 * Create a PieChart 37 * 38 * @param array $data associative array contianing label and values 39 */ 40 protected function pieChart($data) 41 { 42 $data = [ 43 'datasets' => [ 44 [ 45 'data' => array_values($data), 46 ], 47 ], 48 'labels' => array_keys($data) 49 50 ]; 51 52 $this->printGraph('countries', 'pie', $data); 53 } 54 55 /** 56 * Build a PieChart with only the top data shown and all other summarized 57 * 58 * @param string $query The function to call on the Query object to get the data 59 * @param string $key The key containing the label 60 * @param int $max How many discrete values to show before summarizing under "other" 61 */ 62 protected function sumUpPieChart($query, $key, $max = 4) 63 { 64 $result = $this->hlp->getQuery()->$query(); 65 $data = []; 66 $top = 0; 67 foreach ($result as $row) { 68 if ($top < $max) { 69 $data[$row[$key]] = $row['cnt']; 70 } else { 71 $data['other'] += $row['cnt']; 72 } 73 $top++; 74 } 75 $this->pieChart($data); 76 } 77 78 /** 79 * Create a history graph for the given info type 80 * 81 * @param $info 82 */ 83 protected function history($info) 84 { 85 $diff = abs(strtotime($this->from) - strtotime($this->to)); 86 $days = floor($diff / (60 * 60 * 24)); 87 if ($days > 365) { 88 $interval = 'months'; 89 } elseif ($days > 56) { 90 $interval = 'weeks'; 91 } else { 92 $interval = 'days'; 93 } 94 95 $result = $this->hlp->getQuery()->history($info, $interval); 96 97 $data = []; 98 $times = []; 99 foreach ($result as $row) { 100 $data[] = $row['cnt']; 101 if ($interval == 'months') { 102 $times[] = substr($row['time'], 0, 4) . '-' . substr($row['time'], 4, 2); 103 } elseif ($interval == 'weeks') { 104 $times[] = $row['EXTRACT(YEAR FROM dt)'] . '-' . $row['time']; // FIXME 105 } else { 106 $times[] = substr($row['time'], -5); // FIXME 107 } 108 } 109 110 $data = [ 111 'datasets' => [ 112 [ 113 'label' => $this->hlp->getLang('graph_' . $info), 114 'data' => $data, 115 ], 116 ], 117 'labels' => $times 118 ]; 119 120 $this->printGraph("history_$info", 'line', $data); 121 } 122 #region Graphbuilding functions 123 124 public function countries() 125 { 126 $this->sumUpPieChart('countries', 'country'); 127 } 128 129 public function searchengines() 130 { 131 $this->sumUpPieChart('searchengines', 'engine', 3); 132 } 133 134 public function browsers() 135 { 136 $this->sumUpPieChart('browsers', 'browser'); 137 } 138 139 public function os() 140 { 141 $this->sumUpPieChart('os', 'os'); 142 } 143 144 public function topdomain() 145 { 146 $this->sumUpPieChart('topdomain', 'domain'); 147 } 148 149 public function topuser() 150 { 151 $this->sumUpPieChart('topuser', 'user'); 152 } 153 154 public function topeditor() 155 { 156 $this->sumUpPieChart('topeditor', 'user'); 157 } 158 159 public function topgroup() 160 { 161 $this->sumUpPieChart('topgroup', 'group'); 162 } 163 164 public function topgroupedit() 165 { 166 $this->sumUpPieChart('topgroupedit', 'group'); 167 } 168 169 public function viewport() 170 { 171 $result = $this->hlp->getQuery()->viewport(); 172 $data = []; 173 174 foreach ($result as $row) { 175 $data[] = [ 176 'x' => $row['res_x'], 177 'y' => $row['res_y'], 178 'r' => floor($row['cnt'] / 10), 179 ]; 180 } 181 182 $data = [ 183 'datasets' => [ 184 [ 185 'label' => $this->hlp->getLang('viewport'), 186 'data' => $data 187 ] 188 ], 189 ]; 190 191 $this->printGraph('viewport', 'bubble', $data); 192 } 193 194 public function resolution() 195 { 196 $result = $this->hlp->getQuery()->resolution(); 197 $data = []; 198 199 foreach ($result as $row) { 200 $data[] = [ 201 'x' => $row['res_x'], 202 'y' => $row['res_y'], 203 'r' => floor($row['cnt'] / 10), 204 ]; 205 } 206 207 $data = [ 208 'datasets' => [ 209 [ 210 'label' => $this->hlp->getLang('resolution'), 211 'data' => $data 212 ] 213 ], 214 ]; 215 216 $this->printGraph('resolution', 'bubble', $data); 217 } 218 219 220 public function history_page_count() 221 { 222 $this->history('page_count'); 223 } 224 225 public function history_page_size() 226 { 227 $this->history('page_size'); 228 } 229 230 public function history_media_count() 231 { 232 $this->history('media_count'); 233 } 234 235 public function history_media_size() 236 { 237 $this->history('media_size'); 238 } 239 240 public function dashboardviews() 241 { 242 $hours = ($this->from == $this->to); 243 $result = $this->hlp->getQuery()->dashboardviews($hours); 244 $data1 = []; 245 $data2 = []; 246 $data3 = []; 247 $times = []; 248 249 foreach ($result as $time => $row) { 250 $data1[] = (int) $row['pageviews']; 251 $data2[] = (int) $row['sessions']; 252 $data3[] = (int) $row['visitors']; 253 $times[] = $time . ($hours ? 'h' : ''); 254 } 255 256 $data = [ 257 'datasets' => [ 258 [ 259 'label' => $this->hlp->getLang('graph_views'), 260 'data' => $data1, 261 ], 262 [ 263 'label' => $this->hlp->getLang('graph_sessions'), 264 'data' => $data2, 265 ], 266 [ 267 'label' => $this->hlp->getLang('graph_visitors'), 268 'data' => $data3, 269 ], 270 ], 271 'labels' => $times 272 ]; 273 274 $this->printGraph('dashboardviews', 'line', $data); 275 } 276 277 public function dashboardwiki($js = false) 278 { 279 $hours = ($this->from == $this->to); 280 $result = $this->hlp->getQuery()->dashboardwiki($hours); 281 $data1 = []; 282 $data2 = []; 283 $data3 = []; 284 $times = []; 285 286 foreach ($result as $time => $row) { 287 $data1[] = (int) ($row['E'] ?? 0); 288 $data2[] = (int) ($row['C'] ?? 0); 289 $data3[] = (int) ($row['D'] ?? 0); 290 $times[] = $time . ($hours ? 'h' : ''); 291 } 292 $data = [ 293 'datasets' => [ 294 [ 295 'label' => $this->hlp->getLang('graph_edits'), 296 'data' => $data1, 297 ], 298 [ 299 'label' => $this->hlp->getLang('graph_creates'), 300 'data' => $data2, 301 ], 302 [ 303 'label' => $this->hlp->getLang('graph_deletions'), 304 'data' => $data3, 305 ], 306 ], 307 'labels' => $times 308 ]; 309 310 $this->printGraph('dashboardwiki', 'line', $data); 311 } 312 313 /** 314 * @param string $name 315 * @param string $type 316 * @param array $data 317 * @return void 318 */ 319 protected function printGraph(string $name, string $type, array $data) 320 { 321 $json = htmlspecialchars(json_encode($data), ENT_QUOTES, 'UTF-8'); 322 $tpl = ' 323 <chart-component 324 width="%d" 325 height="%d" 326 name="%s" 327 type="%s" 328 data="%s"></chart-component> 329 '; 330 331 echo sprintf($tpl, $this->width, $this->height, $name, $type, $json); 332 } 333 334 #endregion Graphbuilding functions 335} 336