|
By dservos:
CONTRIB-497
* Added flare libbary to repo as it is needed to build the flash front end. Lib is located at /grade/report/visual/flare_visualization/flare/. For more information see http://flare.prefuse.org/
* Added more visualizations.
* Added settings/preferences page for the report.
* Added printable version.
* Added more documentation.
* Added README.txt
* Cleaned up code.
* Fixed a bunch of small bugs.
|
| 22 |
// // |
// // |
| 23 |
/////////////////////////////////////////////////////////////////////////// |
/////////////////////////////////////////////////////////////////////////// |
| 24 |
|
|
| 25 |
|
/** |
| 26 |
|
* File in whiich the grade_report_visual class is defined. |
| 27 |
|
* @package gradebook |
| 28 |
|
*/ |
| 29 |
|
|
| 30 |
require_once($CFG->dirroot . '/grade/report/lib.php'); |
require_once($CFG->dirroot . '/grade/report/lib.php'); |
| 31 |
require_once($CFG->libdir.'/tablelib.php'); |
require_once($CFG->libdir.'/tablelib.php'); |
| 32 |
|
|
| 33 |
|
/// Require all visualization classes |
| 34 |
foreach (glob($CFG->dirroot . '/grade/report/visual/visualizations/visual_*.php') as $filename) { |
foreach (glob($CFG->dirroot . '/grade/report/visual/visualizations/visual_*.php') as $filename) { |
| 35 |
require_once($filename); |
require_once($filename); |
| 36 |
} |
} |
| 37 |
|
|
| 38 |
|
/** |
| 39 |
|
* Class providing the API for the visual report, including harvesters, |
| 40 |
|
* reports, and adaptor methods for turing grades in to visualizations. |
| 41 |
|
* @uses grade_report |
| 42 |
|
* @package gradebook |
| 43 |
|
*/ |
| 44 |
class grade_report_visual extends grade_report { |
class grade_report_visual extends grade_report { |
| 45 |
/** |
/** |
| 46 |
* Capability to view hidden items. |
* Capability to view hidden items. |
|
* TODO: Add a check for hidden items and grades. |
|
| 47 |
* @var bool $canviewhidden |
* @var bool $canviewhidden |
| 48 |
*/ |
*/ |
| 49 |
public $canviewhidden; |
public $canviewhidden; |
| 50 |
|
|
| 51 |
public $nullgradesasmin = false; |
/** |
| 52 |
|
* Array of visualizations available. |
| 53 |
|
* @var array $visualizations |
| 54 |
|
*/ |
| 55 |
private static $visualizations = array(); |
private static $visualizations = array(); |
| 56 |
|
|
| 57 |
/** |
/** |
| 60 |
*/ |
*/ |
| 61 |
public $grades = array(); |
public $grades = array(); |
| 62 |
|
|
| 63 |
|
/** |
| 64 |
|
* Array of data to be sent to the flash front end. |
| 65 |
|
* Data is generated from grades as needed using |
| 66 |
|
* report_data function and $visid. |
| 67 |
|
* @var array $visdata |
| 68 |
|
*/ |
| 69 |
private $visdata = array(); |
private $visdata = array(); |
| 70 |
|
|
| 71 |
private $visid = 'grades_vs_students'; |
/** |
| 72 |
|
* The id of the visualization that has been selected. |
| 73 |
|
* @var string $visid |
| 74 |
|
*/ |
| 75 |
|
public $visid; |
| 76 |
|
|
| 77 |
|
/** |
| 78 |
|
* Array of flashvars to be sent to flash front end. |
| 79 |
|
* @var array $flashvars |
| 80 |
|
*/ |
| 81 |
private $flashvars = array(); |
private $flashvars = array(); |
| 82 |
|
|
| 83 |
|
|
| 84 |
private $flashvarshtml; |
private $flashvarshtml; |
| 85 |
|
|
| 86 |
/** |
/** |
| 103 |
|
|
| 104 |
$this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->course->id)); |
$this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->course->id)); |
| 105 |
|
|
|
if(!is_null($visid)) { |
|
|
$this->visid = $visid; |
|
|
} |
|
|
|
|
| 106 |
/// Set up urls |
/// Set up urls |
| 107 |
$this->baseurl = 'index.php?id=' . $this->courseid; |
$this->baseurl = 'index.php?id=' . $this->courseid; |
| 108 |
$this->pbarurl = 'index.php?id=' . $this->courseid; |
$this->pbarurl = 'index.php?id=' . $this->courseid; |
| 109 |
|
|
| 110 |
|
/// Set the position of the aggregation categorie based on pref |
| 111 |
|
$switch = $this->get_pref('visual', 'aggregationposition'); |
| 112 |
|
if ($switch == '' && isset($CFG->grade_aggregationposition)) { |
| 113 |
|
$switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition); |
| 114 |
|
} |
| 115 |
|
|
| 116 |
/// Build grade tree |
/// Build grade tree |
| 117 |
$this->gtree = new grade_tree($this->courseid, false); |
$this->gtree = new grade_tree($this->courseid, false, $switch); |
| 118 |
|
|
| 119 |
$this->load_visualizations(); |
$this->load_visualizations(); |
| 120 |
|
|
| 121 |
|
if(!is_null($visid) && !empty($visid) && array_key_exists($visid, grade_report_visual::$visualizations)) { |
| 122 |
|
$this->visid = $visid; |
| 123 |
|
} else { |
| 124 |
|
$keys = array_keys(grade_report_visual::$visualizations); |
| 125 |
|
$this->visid = $keys[0]; |
| 126 |
|
} |
| 127 |
|
|
| 128 |
$this->set_up_flashvars(); |
$this->set_up_flashvars(); |
| 129 |
|
|
| 130 |
/// Set up Groups |
/// Set up Groups |
| 131 |
if($visid && grade_report_visual::get_visualization($visid)->usegroups) { |
if($this->visid && grade_report_visual::get_visualization($this->visid)->usegroups) { |
| 132 |
$this->setup_groups(); |
$this->setup_groups(); |
| 133 |
} |
} |
| 134 |
} |
} |
| 143 |
* class that is in a file that starts with visual_ and extends |
* class that is in a file that starts with visual_ and extends |
| 144 |
* visualization directly. |
* visualization directly. |
| 145 |
* @param bool $return if true return visualizations array, else store in $this->visualizations |
* @param bool $return if true return visualizations array, else store in $this->visualizations |
| 146 |
|
* @param object $context the context to use for checking if a user has access to view a visualization. |
| 147 |
* @returns array array of clases that extend visualization |
* @returns array array of clases that extend visualization |
| 148 |
*/ |
*/ |
| 149 |
private function load_visualizations($return=false) { |
private function load_visualizations($return=false, $context = null) { |
| 150 |
global $CFG; |
global $CFG; |
| 151 |
|
|
| 152 |
|
if($context == null) { |
| 153 |
|
$context = $this->context; |
| 154 |
|
} |
| 155 |
|
|
| 156 |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) { |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) { |
| 157 |
$visualizations = array(); |
$visualizations = array(); |
| 158 |
|
|
| 160 |
$filename = substr(basename($path, '.php'), 7); |
$filename = substr(basename($path, '.php'), 7); |
| 161 |
|
|
| 162 |
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) { |
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) { |
| 163 |
|
if($class->capability == null || has_capability($class->capability, $context)) { |
| 164 |
$visualizations[$filename] = $class; |
$visualizations[$filename] = $class; |
| 165 |
} |
} |
| 166 |
} |
} |
| 167 |
|
} |
| 168 |
|
|
| 169 |
if($return) { |
if($return) { |
| 170 |
return $visualizations; |
return $visualizations; |
| 180 |
* Returns the current visualizations being used in the report |
* Returns the current visualizations being used in the report |
| 181 |
* or if none are set, it returns the them as whould be loaded |
* or if none are set, it returns the them as whould be loaded |
| 182 |
* by load_visualizations. |
* by load_visualizations. |
| 183 |
|
* @param object $context the context to use for checking if a user has access to view a visualization. |
| 184 |
* @returns array array of classes that extend visualization |
* @returns array array of classes that extend visualization |
| 185 |
*/ |
*/ |
| 186 |
public function get_visualizations() { |
public function get_visualizations($context=null) { |
| 187 |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) { |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations)) { |
| 188 |
return grade_report_visual::load_visualizations(true); |
return grade_report_visual::load_visualizations(true, $context); |
| 189 |
} else { |
} else { |
| 190 |
return grade_report_visual::$visualizations; |
return grade_report_visual::$visualizations; |
| 191 |
} |
} |
| 192 |
} |
} |
| 193 |
|
|
| 194 |
public function get_visualization($filename) { |
/** |
| 195 |
|
* Returns a specified visulization object. |
| 196 |
|
* @param object $context the context to use for checking if a user has access to view the visualization. |
| 197 |
|
* @returns object visulization object or null if the visulization does not exist or the user does not have access to view it in the given context. |
| 198 |
|
*/ |
| 199 |
|
public function get_visualization($filename, $context=null) { |
| 200 |
|
if($context == null) { |
| 201 |
|
$context = $this->context; |
| 202 |
|
} |
| 203 |
|
|
| 204 |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations[$filename])) { |
if(!isset(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations) || empty(grade_report_visual::$visualizations) || is_null(grade_report_visual::$visualizations[$filename])) { |
| 205 |
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) { |
if(class_exists($filename) && get_parent_class($class = new $filename) == 'visualization' ) { |
| 206 |
|
if($class->capability == null || has_capability($class->capability, $context)) { |
| 207 |
return $class; |
return $class; |
| 208 |
} else { |
} else { |
| 209 |
return null; |
return null; |
| 210 |
} |
} |
| 211 |
} else { |
} else { |
| 212 |
|
return null; |
| 213 |
|
} |
| 214 |
|
} else { |
| 215 |
return grade_report_visual::$visualizations[$filename]; |
return grade_report_visual::$visualizations[$filename]; |
| 216 |
} |
} |
| 217 |
} |
} |
| 301 |
|
|
| 302 |
if ($grades) { |
if ($grades) { |
| 303 |
foreach ($grades as $graderec) { |
foreach ($grades as $graderec) { |
| 304 |
if (in_array($graderec->userid, $userids) and array_key_exists($graderec->itemid, $this->gtree->items)) { // some items may not be present!! |
if (in_array($graderec->userid, $userids) && array_key_exists($graderec->itemid, $this->gtree->items)) { // some items may not be present!! |
| 305 |
$this->grades[$graderec->itemid][$graderec->userid] = new grade_grade($graderec, false); |
$grade = new grade_grade($graderec, false); |
| 306 |
$this->grades[$graderec->itemid][$graderec->userid]->grade_item =& $this->gtree->items[$graderec->itemid]; // db caching |
$grade->grade_item =& $this->gtree->items[$graderec->itemid]; |
| 307 |
|
if((($grade->is_hidden() && $this->canviewhidden && ($this->get_pref('visual', 'usehidden') || is_null($this->get_pref('visual', 'usehidden')))) || !$grade->is_hidden()) |
| 308 |
|
&& (($grade->is_locked() && ($this->get_pref('visual', 'uselocked') || is_null($this->get_pref('visual', 'uselocked')))) || !$grade->is_locked())) { |
| 309 |
|
$this->grades[$graderec->itemid][$graderec->userid] = $grade; |
| 310 |
|
} |
| 311 |
} |
} |
| 312 |
} |
} |
| 313 |
} |
} |
| 314 |
|
|
| 315 |
if($this->nullgradesasmin) { |
if($this->get_pref('visual', 'incompleasmin')) { |
| 316 |
/// prefil grades that do not exist yet |
/// prefil grades that do not exist yet |
| 317 |
foreach ($userids as $userid) { |
foreach ($userids as $userid) { |
| 318 |
foreach ($this->gtree->items as $itemid=>$unused) { |
foreach ($this->gtree->items as $itemid=>$unused) { |
| 319 |
if (!isset($this->grades[$itemid][$userid])) { |
if (!isset($this->grades[$itemid][$userid])) { |
| 320 |
$this->grades[$itemid][$userid] = new grade_grade(); |
$grade = new grade_grade(); |
| 321 |
$this->grades[$itemid][$userid]->itemid = $itemid; |
$grade->itemid = $itemid; |
| 322 |
$this->grades[$itemid][$userid]->userid = $userid; |
$grade->userid = $userid; |
| 323 |
$this->grades[$itemid][$userid]->grade_item =& $this->gtree->items[$itemid]; // db caching |
$grade->grade_item =& $this->gtree->items[$itemid]; // db caching |
| 324 |
$this->grades[$itemid][$userid]->finalgrade = $this->grades[$itemid][$userid]->grade_item->mingrade; |
$grade->finalgrade = $this->gtree->items[$itemid]->grademin; |
|
} |
|
|
} |
|
|
} |
|
|
} |
|
| 325 |
|
|
| 326 |
/*$this->finalgrades = array(); |
if((($grade->is_hidden() && $this->canviewhidden && ($this->get_pref('visual', 'usehidden') || is_null($this->get_pref('visual', 'usehidden')))) || !$grade->is_hidden()) |
| 327 |
|
&& (($grade->is_locked() && ($this->get_pref('visual', 'uselocked') || is_null($this->get_pref('visual', 'uselocked')))) || !$grade->is_locked())) { |
| 328 |
/// Build finalgrades array and filliter out unwanted grades. |
$this->grades[$itemid][$userid] = $grade; |
|
foreach ($this->gtree->items as $id=>$item) { |
|
|
if(($item->gradetype == GRADE_TYPE_SCALE && ($this->get_pref('stats', 'showscaleitems') || is_null($this->get_pref('stats', 'showscaleitems')))) |
|
|
|| ($item->gradetype == GRADE_TYPE_VALUE && ($this->get_pref('stats', 'showvalueitems') || is_null($this->get_pref('stats', 'showvalueitems'))))) { |
|
|
$this->finalgrades[$id] = array(); |
|
|
$i = 0; |
|
|
|
|
|
if(isset($this->grades[$id]) && !is_null($this->grades[$id])) { |
|
|
foreach ($this->grades[$id] as $grade) { |
|
|
if( (($grade->is_hidden() && ($this->get_pref('stats', 'usehidden') || is_null($this->get_pref('stats', 'usehidden')))) || !$grade->is_hidden()) |
|
|
&& (($grade->is_locked() && ($this->get_pref('stats', 'uselocked') || is_null($this->get_pref('stats', 'uselocked')))) || !$grade->is_locked())) { |
|
|
if($this->get_pref('stats', 'incompleasmin') && is_null($grade->finalgrade)) { |
|
|
$this->finalgrades[$id][$i] = $item->grademin; |
|
|
$i++; |
|
|
} elseif(!is_null($grade->finalgrade)) { |
|
|
$this->finalgrades[$id][$i] = $grade->finalgrade; |
|
|
$i++; |
|
| 329 |
} |
} |
| 330 |
} |
} |
| 331 |
} |
} |
| 332 |
} |
} |
| 333 |
} |
} |
|
}*/ |
|
| 334 |
} |
} |
| 335 |
|
|
| 336 |
/** |
/** |
| 337 |
* TODO: have this make the data depending on what kind of visulsation |
* Generates the data for a visualization or all visualizations to be sent to |
| 338 |
* is needed rather then a singal visulasztion witch is currently hardcoded. |
* the front end. |
| 339 |
|
* @param bool $all if true loads the data for all visualizations into visdata, else loads only the visualization selected by visid. |
| 340 |
*/ |
*/ |
| 341 |
public function report_data($all = false) { |
public function report_data($all = false) { |
| 342 |
if($all) { |
if($all) { |
| 351 |
} |
} |
| 352 |
} |
} |
| 353 |
|
|
| 354 |
|
/** |
| 355 |
|
* Generates the values of the flashvars that will be sent to the |
| 356 |
|
* flash front end and encodes them as html in flashvarshtml so |
| 357 |
|
* they can be droped in to the flash tag. |
| 358 |
|
*/ |
| 359 |
private function set_up_flashvars() { |
private function set_up_flashvars() { |
| 360 |
global $USER, $SESSION, $CFG; |
global $USER, $SESSION, $CFG; |
| 361 |
|
|
| 379 |
} |
} |
| 380 |
|
|
| 381 |
/** |
/** |
| 382 |
*TODO: Have this call on flex.php to generate html for the report., |
* Returns or prints html for the report. |
| 383 |
*rather then having it hardcoded as it is now. |
* HTML produced is based on flex.php and the values in this calss. |
| 384 |
|
* @param bool $printerversion if true the HTML will be for the printerversion of the report. |
| 385 |
|
* @param bool $return if true the HTML will be returned as a string rather then echoed. |
| 386 |
|
* @returns string if $return is true a string of the HTML will be retruned. |
| 387 |
*/ |
*/ |
| 388 |
public function adapt_html($printerversion = false, $return = false) { |
public function adapt_html($printerversion = false, $return = false) { |
| 389 |
global $CFG; |
global $CFG; |
| 391 |
$flashvarshtml = $this->flashvarshtml; |
$flashvarshtml = $this->flashvarshtml; |
| 392 |
$visual = $this->get_visualization($this->visid); |
$visual = $this->get_visualization($this->visid); |
| 393 |
|
|
| 394 |
|
if($printerversion) { |
| 395 |
|
$flashvarshtml .= '&printerversion=true'; |
| 396 |
|
} else { |
| 397 |
|
$flashvarshtml .= '&printerversion=false'; |
| 398 |
|
} |
| 399 |
|
|
| 400 |
ob_start(); |
ob_start(); |
| 401 |
require($CFG->dirroot.'/grade/report/visual/flex.php'); |
require($CFG->dirroot.'/grade/report/visual/flex.php'); |
| 402 |
$this->html = ob_get_clean(); |
$this->html = ob_get_clean(); |
| 408 |
} |
} |
| 409 |
} |
} |
| 410 |
|
|
| 411 |
|
/** |
| 412 |
|
* Adapts $visdata to a fromat that can be read by the flash front end. |
| 413 |
|
* TODO: Have options for diffrent fromats rather then just tab format. |
| 414 |
|
* @param bool $return if true the data is returned in a string, else it is echoed. |
| 415 |
|
* @returns string if $return is true a string of the adapted data will be returned. |
| 416 |
|
*/ |
| 417 |
public function adapt_data($return = false) { |
public function adapt_data($return = false) { |
| 418 |
if($return) { |
if($return) { |
| 419 |
return $this->get_tab(true); |
return $this->get_tab(true); |
| 422 |
} |
} |
| 423 |
} |
} |
| 424 |
|
|
| 425 |
|
/** |
| 426 |
|
* Generates the HTML for a selector feild witch lists the visualizations avaible |
| 427 |
|
* to the current user. |
| 428 |
|
* @param bool $return if true the HTML is retruned as a string, otherwise it is echoed. |
| 429 |
|
* @returns string if $return is true, the HTML is returned as a string. |
| 430 |
|
*/ |
| 431 |
public function visualization_selector($return = false) { |
public function visualization_selector($return = false) { |
| 432 |
$visuals = $this->get_visualizations(); |
$visuals = $this->get_visualizations(); |
| 433 |
$visualmenu = array(); |
$visualmenu = array(); |
| 450 |
} |
} |
| 451 |
} |
} |
| 452 |
|
|
| 453 |
|
/** |
| 454 |
|
* Truncates a string to $max chars long and adds $end to the string |
| 455 |
|
* if it is more then $max chars. The resulting string will allways be at |
| 456 |
|
* most $max chars long. $end must be shorter then $max long. |
| 457 |
|
* @param string $string the string to truncate. |
| 458 |
|
* @param int $max the maxium length of the string. |
| 459 |
|
* @param string $end a string that will be appened to the end of the truncated string if it is over $max in length. |
| 460 |
|
* @returns string returns the truncated string if $string is over $max in length, other wise returns $string. |
| 461 |
|
*/ |
| 462 |
public static function truncate($string, $max = 25, $end = '...') { |
public static function truncate($string, $max = 25, $end = '...') { |
| 463 |
if(strlen($string) <= $max) { |
if(strlen($string) <= $max) { |
| 464 |
return $string; |
return $string; |
| 468 |
} |
} |
| 469 |
|
|
| 470 |
/** |
/** |
|
* Returns the data for a visulazation in json format. |
|
|
* TODO: Use moodle's json encoding functions rather then phps. |
|
|
* @param boolean $return if true return a string, other wise echo the data. |
|
|
* @return string If return is set to true, returns a string of the data in json format. |
|
|
*/ |
|
|
private function get_json($return = true) { |
|
|
if ($return) { |
|
|
return json_encode($this->visdata[$this->visid]); |
|
|
} else { |
|
|
echo json_encode($this->visdata[$this->visid]); |
|
|
} |
|
|
} |
|
|
|
|
|
/** |
|
| 471 |
* Returns the data for a visulasation in tab format. |
* Returns the data for a visulasation in tab format. |
| 472 |
* @param boolean $return if true return a string, other wise echo the data. |
* @param boolean $return if true return a string, other wise echo the data. |
| 473 |
* @return string If return is set to true, returns a string of the data in tab format. |
* @return string If return is set to true, returns a string of the data in tab format. |