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 topuser() 145 { 146 $this->sumUpPieChart('topuser', 'user'); 147 } 148 149 public function topeditor() 150 { 151 $this->sumUpPieChart('topeditor', 'user'); 152 } 153 154 public function topgroup() 155 { 156 $this->sumUpPieChart('topgroup', 'group'); 157 } 158 159 public function topgroupedit() 160 { 161 $this->sumUpPieChart('topgroupedit', 'group'); 162 } 163 164 public function viewport() 165 { 166 $result = $this->hlp->getQuery()->viewport(); 167 $data = []; 168 169 foreach ($result as $row) { 170 $data[] = [ 171 'x' => $row['res_x'], 172 'y' => $row['res_y'], 173 'r' => floor($row['cnt'] / 10), 174 ]; 175 } 176 177 $data = [ 178 'datasets' => [ 179 [ 180 'label' => $this->hlp->getLang('viewport'), 181 'data' => $data 182 ] 183 ], 184 ]; 185 186 $this->printGraph('viewport', 'bubble', $data); 187 } 188 189 public function resolution() 190 { 191 $result = $this->hlp->getQuery()->resolution(); 192 $data = []; 193 194 foreach ($result as $row) { 195 $data[] = [ 196 'x' => $row['res_x'], 197 'y' => $row['res_y'], 198 'r' => floor($row['cnt'] / 10), 199 ]; 200 } 201 202 $data = [ 203 'datasets' => [ 204 [ 205 'label' => $this->hlp->getLang('resolution'), 206 'data' => $data 207 ] 208 ], 209 ]; 210 211 $this->printGraph('resolution', 'bubble', $data); 212 } 213 214 215 public function history_page_count() 216 { 217 $this->history('page_count'); 218 } 219 220 public function history_page_size() 221 { 222 $this->history('page_size'); 223 } 224 225 public function history_media_count() 226 { 227 $this->history('media_count'); 228 } 229 230 public function history_media_size() 231 { 232 $this->history('media_size'); 233 } 234 235 public function dashboardviews() 236 { 237 $hours = ($this->from == $this->to); 238 $result = $this->hlp->getQuery()->dashboardviews($hours); 239 $data1 = []; 240 $data2 = []; 241 $data3 = []; 242 $times = []; 243 244 foreach ($result as $time => $row) { 245 $data1[] = (int) $row['pageviews']; 246 $data2[] = (int) $row['sessions']; 247 $data3[] = (int) $row['visitors']; 248 $times[] = $time . ($hours ? 'h' : ''); 249 } 250 251 $data = [ 252 'datasets' => [ 253 [ 254 'label' => $this->hlp->getLang('graph_views'), 255 'data' => $data1, 256 ], 257 [ 258 'label' => $this->hlp->getLang('graph_sessions'), 259 'data' => $data2, 260 ], 261 [ 262 'label' => $this->hlp->getLang('graph_visitors'), 263 'data' => $data3, 264 ], 265 ], 266 'labels' => $times 267 ]; 268 269 $this->printGraph('dashboardviews', 'line', $data); 270 } 271 272 public function dashboardwiki($js = false) 273 { 274 $hours = ($this->from == $this->to); 275 $result = $this->hlp->getQuery()->dashboardwiki($hours); 276 $data1 = []; 277 $data2 = []; 278 $data3 = []; 279 $times = []; 280 281 foreach ($result as $time => $row) { 282 $data1[] = (int) ($row['E'] ?? 0); 283 $data2[] = (int) ($row['C'] ?? 0); 284 $data3[] = (int) ($row['D'] ?? 0); 285 $times[] = $time . ($hours ? 'h' : ''); 286 } 287 $data = [ 288 'datasets' => [ 289 [ 290 'label' => $this->hlp->getLang('graph_edits'), 291 'data' => $data1, 292 ], 293 [ 294 'label' => $this->hlp->getLang('graph_creates'), 295 'data' => $data2, 296 ], 297 [ 298 'label' => $this->hlp->getLang('graph_deletions'), 299 'data' => $data3, 300 ], 301 ], 302 'labels' => $times 303 ]; 304 305 $this->printGraph('dashboardwiki', 'line', $data); 306 } 307 308 /** 309 * @param string $name 310 * @param string $type 311 * @param array $data 312 * @return void 313 */ 314 protected function printGraph(string $name, string $type, array $data) 315 { 316 $json = htmlspecialchars(json_encode($data), ENT_QUOTES, 'UTF-8'); 317 $tpl = ' 318 <chart-component 319 width="%d" 320 height="%d" 321 name="%s" 322 type="%s" 323 data="%s"></chart-component> 324 '; 325 326 echo sprintf($tpl, $this->width, $this->height, $name, $type, $json); 327 } 328 329 #endregion Graphbuilding functions 330} 331