-
Notifications
You must be signed in to change notification settings - Fork 0
6.4 ChartJS Module
Juan Morales edited this page Mar 5, 2021
·
4 revisions
This modules generates a simple graphic using the ChartJS javascript library.
The idea behind this module is to provide an idea/example, about how to generate graphics using JS libraries.
Please check the comments
<?php declare(strict_types=1);
namespace Footprint\Modules;
use Footprint\Interfaces\IModule;
use Footprint\Tracker;
class ChartJS implements IModule
{
//Module ID
const MODULE_ID = "CHARTJS";
protected $keys = [];
protected $data = [];
protected $labels = [];
protected $fileHandler;
/*
* The module takes two arguments in the constructor.
* 1) $filename : which holds an string with the filepath/filename where the final report will be generated.
* 2) $keys : an array that holds the "keys" that this module is interested in. Lets imagine that we a using the Tracker with multiple modules, and of thos modules is the Memory Module. So at the end we would like to generate a chart (in this case a line chart) only for the values logged in the Memory Module, but specifucally the keys Memory::KEY_MEM_USAGE and Memory::KEY_MEM_PEAK , if so ... we pass this values in the $keys array.
*/
public function __construct(string $filename, array $keys = []) {
//We gnerate the file handler to be used during the chart generation
if (!$this->fileHandler = fopen($filename, "w+")) {
throw new Exception("Could not create file ${$filename}");
}
$this->keys = $keys;
}
public function getId() {
return self::MODULE_ID;
}
public function onInit(Tracker &$tracker) {
return;
}
/*
* When the Tracker is finished, will invoke this method.
* Basically the report content, or most of it, is saved in a variable called $reportTemplate .
*
* The module uses the content of this variable to generate the report (the line chart).
* The content of $reportTemplate is basically that, a template that will be filld in.
*
* You can see that the template value has some "tags" like {{labels}} which will be use later,
* to inject/replace the tag, by actual/real data coming from the Tracker.
*/
public function onEnd(Tracker &$tracker) {
$reportTemplate = '
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
</head>
<body>
<div style="width: 100%; height: 30%;">
<canvas id="myChart"></canvas>
</div>
<script>
let ctx = document.getElementById("myChart").getContext("2d");
let myData = {
labels: {{labels}},
datasets:[
{{data}}
],
};
let myOptions = {
tooltips: {
mode: "index",
intersect: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}],
xAxes: [{
type: "time",
distribution: "series",
ticks: {
source: "auto",
autoSkip: true
},
time: {
unit: "second",
stepSize: 1,
}
}]
}
};
let myChart = new Chart(ctx, {
type: "line",
data: myData,
options: myOptions
});
</script>
</body>
</html>';
$colors = [
"red",
"blue",
"green",
"black",
"purple",
"orange"
];
$colorIndex = 0;
//Start PHP code resposible to generate a JS string to be injected in the $reportTemplate
$labels = json_encode($this->labels);
$datasetTemplate = "{
label: '{{label}}',
data: {{data}},
borderColor: '{{color}}',
pointBackgroundColor: '{{color}}',
borderWidth: 1,
fill: false,
lineTension: 0.1
},";
$data = "";
foreach($this->keys as $key) {
$tmp = str_replace("{{label}}", $key, $datasetTemplate);
$tmp = str_replace("{{data}}", json_encode($this->data[$key]), $tmp);
$tmp = str_replace("{{color}}", $colors[$colorIndex], $tmp);
$data .= $tmp;
$colorIndex++;
if ($colorIndex == count($colors) - 1) {
$colorIndex = 0;
}
}
$data[-1] = \chr(32);
//End of previous Start
$reportTemplate = str_replace("{{labels}}", $labels, $reportTemplate);
$reportTemplate = str_replace("{{data}}", $data, $reportTemplate);
//Then we write the content of $reportTemplate into the report
fwrite($this->fileHandler, $reportTemplate);
fclose($this->fileHandler);
return;
}
public function onLoad(Tracker &$tracker) {
return;
}
public function onUnload(Tracker &$tracker) {
return;
}
/*
* Every time the Tracker sends a log(), we store the values of the keys
* we are interested in (during the __construct).
*/
public function onLog(Tracker &$tracker) {
$this->labels[] = explode("_", $tracker->getLogId())[0];
foreach ($this->keys as $key) {
$this->data[$key][] = $tracker->getLogDataByKey($key);
}
return;
}
public function onLogBuild(Tracker &$tracker) {
return;
}
/*
* Method to "manually" add keys to the module.
* This needs to be call before the Tracker starts.
*/
public function addKey(string $key) {
$this->keys[] = $key;
return $this;
}
public function removeKey(string $key) {
unset($this->keys[$key]);
return $this;
}
public function getKeys() : array {
return [];
}
}
and that is it!
Sample output containing all keys from the Memory and Time modules.