You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

240 lines
8.1 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Tiki\Process\Process;
function wikiplugin_chartjs_info()
{
return [
'name' => tr('Chart JS'),
'documentation' => 'PluginChartJS',
'description' => tra('Create a JS Chart'),
'prefs' => ['wikiplugin_chartjs'],
'body' => tr('JSON encoded array for data and options.'),
'tags' => ['advanced'],
'introduced' => 16,
'params' => [
'id' => [
'name' => tra('Chart Id'),
'description' => tr('A custom ID for the chart.'),
'filter' => 'text',
'default' => 'tikiChart1, tikiChart2 etc',
'since' => '16.0',
],
'type' => [
'name' => tra('Chart Type'),
'description' => tr('The type of chart. Currently works with pie, bar and doughnut'),
'filter' => 'text',
'default' => 'pie',
'since' => '16.0',
],
'height' => [
'name' => tra('Chart Height'),
'description' => tr('The height of the chart in px'),
'filter' => 'text',
'default' => '200',
'since' => '16.0',
],
'width' => [
'name' => tra('Chart Width'),
'description' => tr('The width of the chart in px'),
'filter' => 'text',
'default' => '200',
'since' => '16.0',
],
'values' => [
'name' => tra('Chart data values'),
'description' => tr('Colon-separated values for the chart (required if not using JSON encoded data in the plugin body)'),
'filter' => 'text',
'default' => '',
'since' => '16.0',
],
'data_labels' => [
'name' => tra('Chart data labels'),
'description' => tr('Colon-separated labels for the datasets in the chart. Max 10, if left empty'),
'filter' => 'text',
'default' => 'A:B:C:D:E:F:G:H:I:J',
'since' => '16.0',
],
'data_colors' => [
'name' => tra('Chart colors'),
'description' => tr('Colon-separated colors for the datasets in the chart. Max 10, if left empty'),
'filter' => 'text',
'default' => 'red:blue:green:purple:grey:orange:yellow:black:brown:cyan',
'since' => '16.0',
],
'data_highlights' => [
'name' => tra('Chart highlight'),
'description' => tr('Colon-separated color of chart section when highlighted'),
'filter' => 'text',
'default' => '',
'since' => '16.0',
],
'debug' => [
'name' => tra('Debug Mode'),
'description' => tr('Uses the non-minified version of the chart.js library for easier debugging.'),
'filter' => 'digits',
'default' => 0,
'advanced' => true,
'since' => '18.3',
],
],
'iconname' => 'pie-chart',
];
}
function wikiplugin_chartjs($data, $params)
{
global $base_url;
static $instance = 0;
$instance++;
if (empty($params['id'])) {
$params['id'] = "tikiChart$instance";
}
//set defaults
$plugininfo = wikiplugin_chartjs_info();
$defaults = [];
foreach ($plugininfo['params'] as $key => $param) {
$defaults[$key] = $param['default'];
}
$params = array_merge($defaults, $params);
if (empty($params['data_highlights'])) {
$params['data_highlights'] = $params['data_colors'];
}
if (empty(trim($data))) {
$values = array_filter(explode(':', $params['values']));
$data_labels = array_filter(explode(':', $params['data_labels']));
$data_colors = array_filter(explode(':', $params['data_colors']));
$data_highlights = array_filter(explode(':', $params['data_highlights']));
if (empty($values)) {
return tr('Values must be set for chart');
}
$data = [
'labels' => array_slice($data_labels, 0, count($values)),
'datasets' => [
[
'data' => $values,
'backgroundColor' => array_slice($data_colors, 0, count($values)),
'hoverBackgroundColor' => array_slice($data_highlights, 0, count($values)),
],
],
];
$options = [];
} else {
$data = json_decode($data, true);
if (isset($data['options']) && isset($data['data'])) {
$options = $data['options'];
$data = $data['data'];
}
}
$to_PDF = ! empty($_REQUEST['display']) && $_REQUEST['display'] == 'pdf';
$min = $params['debug'] ? '' : 'min.';
// Disable animation
if ($to_PDF) {
$options['animation'] = [ // 'animation: { duration: 0 }'
'duration' => 0,
];
}
$script = '
var chartjs_' . $params['id'] . ' = new Chart("' . $params['id'] . '", {
type: "' . $params['type'] . '",
data: ' . json_encode($data) . ',
options: ' . json_encode($options) . '
});
';
$canvas = '<canvas id="' . $params['id'] . '" width="' . $params['width'] . '" height="' . $params['height'] . '"></canvas>';
if (! $to_PDF) {
TikiLib::lib('header')->add_jsfile("vendor_bundled/vendor/npm-asset/chart.js/dist/Chart.bundle.{$min}js")
->add_jq_onready('setTimeout(function () {' . $script . '}, 500);');
return '<div class="tiki-chartjs">' . $canvas . '</div>';
}
// PDF export related logic
$html_content = <<<HTML
<script src="{$base_url}vendor_bundled/vendor/npm-asset/chart.js/dist/Chart.bundle.{$min}js"></script>
<div>
$canvas
</div>
<script>
$script
</script>
HTML;
$scriptHash = md5($script);
$cacheKey = 'chart_';
$cacheLib = TikiLib::lib('cache');
if (! $cacheLib->isCached($scriptHash, $cacheKey)) {
$htmlFile = writeTempFile($html_content, '', true, 'wikiplugin_chart_', '.html');
$casperBin = implode(DIRECTORY_SEPARATOR, [TIKI_PATH, 'bin', 'casperjs']);
if (! file_exists($casperBin)) {
return tr('Tiki needs the jerome-breton/casperjs-installer to convert charts to PNG. If you do not have permission to install this package, ask the site administrator.');
}
$casperjsScript = <<<JS
var casper = require('casper').create();
casper.start('{$htmlFile}', function() {
this.echo(this.captureBase64('png', 'div'));
});
casper.run();
JS;
$casperFile = writeTempFile($casperjsScript, '', true, 'wikiplugin_chart_', '.js');
$command = $casperBin . ' ' . $casperFile;
$process = new Process($command);
if (! empty($params['timeout'])) {
$process->setTimeout($params['timeout']);
$process->setIdleTimeout($params['timeout']);
}
try {
$process->run();
} catch (ProcessTimedOutException $e) {
$logsLib = TikiLib::lib('logs');
$logsLib->add_log('Casperjs', $e->getMessage());
\Feedback::error(tr('Failed to generate chart image using Casperjs. Please check Tiki Action Log for more information.'));
} finally {
unlink($htmlFile);
unlink($casperFile);
}
if ($process->isSuccessful()) {
$base64 = $process->getOutput();
} else {
return false;
}
$cacheLib->cacheItem($scriptHash, $base64, $cacheKey);
} else {
$base64 = $cacheLib->getCached($scriptHash, $cacheKey);
}
$canvas = <<<HTML
<img src="data:image/jpeg;charset=utf-8;base64, {$base64}"/>
HTML;
return '<div class="tiki-chartjs">' . $canvas . '</div>';
}