1<?php 2/* Copyright (c) 1998-2010 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4include_once "Services/Chart/classes/class.ilChartLegend.php"; 5 6/** 7 * Abstract Chart generator base class 8 * 9 * @author Jörg Lützenkirchen <luetzenkirchen@leifos.com> 10 * @version $Id$ 11 * @ingroup ServicesChart 12 */ 13abstract class ilChart 14{ 15 /** 16 * @var ilTemplate 17 */ 18 protected $tpl; 19 20 protected $id; // [string] 21 protected $width; // [string] 22 protected $height; // [string] 23 protected $data; // [array] 24 protected $legend; // [ilChartLegend] 25 protected $shadow; // [int] 26 protected $colors; // [array] 27 protected $auto_resize; // [bool] 28 protected $stacked; // [bool] 29 30 const TYPE_GRID = 1; 31 const TYPE_PIE = 2; 32 const TYPE_SPIDER = 3; 33 34 /** 35 * Constructor 36 * 37 * @param string $a_id 38 */ 39 protected function __construct($a_id) 40 { 41 global $DIC; 42 43 $this->tpl = $DIC["tpl"]; 44 $this->id = $a_id; 45 $this->data = array(); 46 47 $this->setShadow(2); 48 } 49 50 /** 51 * Get type instance 52 * 53 * @param int $a_type 54 * @param string $a_id 55 * @return ilChart 56 */ 57 public static function getInstanceByType($a_type, $a_id) 58 { 59 switch ($a_type) { 60 case self::TYPE_GRID: 61 include_once "Services/Chart/classes/class.ilChartGrid.php"; 62 return new ilChartGrid($a_id); 63 64 case self::TYPE_PIE: 65 include_once "Services/Chart/classes/class.ilChartPie.php"; 66 return new ilChartPie($a_id); 67 68 case self::TYPE_SPIDER: 69 include_once "Services/Chart/classes/class.ilChartSpider.php"; 70 return new ilChartSpider($a_id); 71 } 72 } 73 74 /** 75 * Get data series instance 76 * 77 * @return ilChartData 78 */ 79 abstract public function getDataInstance($a_type = null); 80 81 /** 82 * Validate data series 83 * 84 * @return bool 85 */ 86 abstract protected function isValidDataType(ilChartData $a_series); 87 88 /** 89 * Basic validation 90 * 91 * @return bool 92 */ 93 protected function isValid() 94 { 95 if (sizeof($this->data)) { 96 return true; 97 } 98 return false; 99 } 100 101 /** 102 * Set chart size 103 * 104 * @param int $a_x 105 * @param int $a_y 106 */ 107 public function setSize($a_x, $a_y) 108 { 109 $this->width = $a_x; 110 $this->height = $a_y; 111 } 112 113 /** 114 * Add data series 115 * 116 * @param ilChartData $a_series 117 * @param mixed $a_id 118 * @return mixed index 119 */ 120 public function addData(ilChartData $a_series, $a_idx = null) 121 { 122 if ($this->isValidDataType($a_series)) { 123 if ($a_idx === null) { 124 $a_idx = sizeof($this->data); 125 } 126 $this->data[$a_idx] = $a_series; 127 return $a_idx; 128 } 129 } 130 131 /** 132 * Set chart legend 133 * 134 * @param ilChartLegend $a_legend 135 */ 136 public function setLegend(ilChartLegend $a_legend) 137 { 138 $this->legend = $a_legend; 139 } 140 141 /** 142 * Set colors 143 * 144 * @param array $a_values 145 */ 146 public function setColors($a_values) 147 { 148 foreach ($a_values as $color) { 149 if (self::isValidColor($color)) { 150 $this->colors[] = $color; 151 } 152 } 153 } 154 155 /** 156 * Get colors 157 * 158 * @return array 159 */ 160 public function getColors() 161 { 162 return $this->colors; 163 } 164 165 /** 166 * Validate html color code 167 * 168 * @param string $a_value 169 * @return bool 170 */ 171 public static function isValidColor($a_value) 172 { 173 if (preg_match("/^#[0-9a-f]{3}$/i", $a_value, $match)) { 174 return true; 175 } elseif (preg_match("/^#[0-9a-f]{6}$/i", $a_value, $match)) { 176 return true; 177 } 178 } 179 180 /** 181 * Render html color code 182 * 183 * @param string $a_value 184 * @param float $a_opacity 185 * @return string 186 */ 187 public static function renderColor($a_value, $a_opacity = 1) 188 { 189 if (self::isValidColor($a_value)) { 190 if (strlen($a_value) == 4) { 191 return "rgba(" . hexdec($a_value[1] . $a_value[1]) . ", " . 192 hexdec($a_value[2] . $a_value[2]) . ", " . 193 hexdec($a_value[3] . $a_value[3]) . ", " . $a_opacity . ")"; 194 } else { 195 return "rgba(" . hexdec($a_value[1] . $a_value[2]) . ", " . 196 hexdec($a_value[3] . $a_value[4]) . ", " . 197 hexdec($a_value[5] . $a_value[6]) . ", " . $a_opacity . ")"; 198 } 199 } 200 } 201 202 /** 203 * Set shadow 204 * 205 * @param int $a_value 206 */ 207 public function setShadow($a_value) 208 { 209 $this->shadow = (int) $a_value; 210 } 211 212 /** 213 * Get shadow 214 * 215 * @return int 216 */ 217 public function getShadow() 218 { 219 return $this->shadow; 220 } 221 222 /** 223 * Toggle auto-resizing on window resize/redraw 224 * 225 * @param bool $a_value 226 */ 227 public function setAutoResize($a_value) 228 { 229 $this->auto_resize = (bool) $a_value; 230 } 231 232 /** 233 * Toggle stacking 234 * 235 * @param bool $a_value 236 */ 237 public function setStacked($a_value) 238 { 239 $this->stacked = (bool) $a_value; 240 } 241 242 /** 243 * Init JS script files 244 */ 245 protected function initJS() 246 { 247 $tpl = $this->tpl; 248 249 include_once "Services/jQuery/classes/class.iljQueryUtil.php"; 250 iljQueryUtil::initjQuery(); 251 252 $tpl->addJavascript("Services/Chart/js/flot/excanvas.min.js"); 253 $tpl->addJavascript("Services/Chart/js/flot/jquery.flot.min.js"); 254 255 if ((bool) $this->auto_resize) { 256 // #13108 257 $tpl->addJavascript("Services/Chart/js/flot/jquery.flot.resize.min.js"); 258 } 259 260 if ((bool) $this->stacked) { 261 $tpl->addJavascript("Services/Chart/js/flot/jquery.flot.stack.min.js"); 262 } 263 264 $this->addCustomJS(); 265 } 266 267 /** 268 * Add type-specific JS script 269 */ 270 protected function addCustomJS() 271 { 272 } 273 274 /** 275 * Convert (global) properties to flot config 276 * 277 * @param object $a_options 278 */ 279 public function parseGlobalOptions(stdClass $a_options) 280 { 281 } 282 283 /** 284 * Render 285 */ 286 public function getHTML() 287 { 288 if (!$this->isValid()) { 289 return; 290 } 291 292 $this->initJS(); 293 294 $chart = new ilTemplate("tpl.grid.html", true, true, "Services/Chart"); 295 $chart->setVariable("ID", $this->id); 296 297 if ($this->width) { 298 if (is_numeric($this->width)) { 299 $chart->setVariable("WIDTH", "width:" . $this->width . "px;"); 300 } else { 301 $chart->setVariable("WIDTH", "width:" . $this->width . ";"); 302 } 303 } 304 if ($this->height) { 305 if (is_numeric($this->height)) { 306 $chart->setVariable("HEIGHT", "height:" . $this->height . "px;"); 307 } else { 308 $chart->setVariable("HEIGHT", "height:" . $this->height . ";"); 309 } 310 } 311 312 313 // (series) data 314 315 $json_series = array(); 316 foreach ($this->data as $series) { 317 $series->parseData($json_series); 318 } 319 $chart->setVariable("SERIES", json_encode($json_series)); 320 321 322 // global options 323 324 $json_options = new stdClass(); 325 $json_options->series = new stdClass(); 326 $json_options->series->shadowSize = (int) $this->getShadow(); 327 $json_options->series->lines = new stdClass(); 328 $json_options->series->lines->show = false; 329 $json_options->series->stack = (bool) $this->stacked; 330 331 foreach ($this->data as $series) { 332 $series->parseGlobalOptions($json_options, $this); 333 } 334 335 $this->parseGlobalOptions($json_options); 336 337 $colors = $this->getColors(); 338 if ($colors) { 339 $json_options->colors = array(); 340 foreach ($colors as $color) { 341 $json_options->colors[] = self::renderColor($color); 342 } 343 } 344 345 // legend 346 $json_options->legend = new stdClass(); 347 if (!$this->legend) { 348 $json_options->legend->show = false; 349 } else { 350 $this->legend->parseOptions($json_options->legend); 351 } 352 353 $chart->setVariable("OPTIONS", json_encode($json_options)); 354 355 $ret = $chart->get(); 356 return $ret; 357 } 358 359 /* 360 ilChart 361 ->setColors 362 ->setHover() [tooltip?] 363 [->setClick] 364 ->setZooming 365 ->setPanning 366 ->setTooltip 367 ->addData[Series] 368 - labels 369 - type 370 - pie: nur 1x 371 - bar, lines, points, steps, stacked? 372 - highlight?! 373 => min/max, transmission type (google api) 374 375 376 grid-based 377 ->setGrid 378 ->setTicks(color, size, decimals, length) 379 ->addAxisX (multiple, Zero) [id, mode, position, color, label] 380 ->addAxisY (multiple?) [id, mode, position, color, label] 381 ->setBackgroundFill(opacity, color/gradient) 382 ->setThreshold(int/float) 383 ->setToggles(bool) 384 385 pie 386 ->setCollapse(int/float, color, label) 387 ->setRotation(int angle?) 388 ->setRadius(inner, outer) 389 */ 390} 391