mirror of
https://github.com/VTECRM/vtenext.git
synced 2026-02-26 16:18:47 +00:00
1892 lines
62 KiB
PHP
1892 lines
62 KiB
PHP
<?php
|
|
/*************************************
|
|
* SPDX-FileCopyrightText: 2009-2020 Vtenext S.r.l. <info@vtenext.com>
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
************************************/
|
|
require_once('data/CRMEntity.php');
|
|
require_once('data/Tracker.php');
|
|
require_once('modules/PickList/PickListUtils.php');
|
|
require_once('modules/Reports/ReportRun.php');
|
|
|
|
/* crmv@82770 - support for ChartJS */
|
|
/* crmv@83040 - support for drill-down */
|
|
|
|
// pChart classes
|
|
require_once('include/pChart/class/pData.class.php');
|
|
require_once('include/pChart/class/pDraw.class.php');
|
|
require_once('include/pChart/class/pImage.class.php');
|
|
require_once('include/pChart/class/pPie.class.php');
|
|
require_once('include/pChart/class/pSplit.class.php');
|
|
require_once('include/pChart/class/pScatter.class.php'); // crmv@53923
|
|
|
|
class Charts extends CRMEntity {
|
|
|
|
public $db, $log; // Used in class functions of CRMEntity
|
|
|
|
public $table_name = 'vte_charts';
|
|
public $table_index= 'chartid';
|
|
public $column_fields = Array();
|
|
|
|
/** Indicator if this is a custom module or standard module */
|
|
public $IsCustomModule = true;
|
|
|
|
/**
|
|
* Mandatory table for supporting custom fields.
|
|
*/
|
|
public $customFieldTable = Array('vte_chartscf', 'chartid');
|
|
|
|
/**
|
|
* Mandatory for Saving, Include tables related to this module.
|
|
*/
|
|
public $tab_name = Array('vte_crmentity', 'vte_charts', 'vte_chartscf', 'vte_chartscache');
|
|
|
|
/**
|
|
* Mandatory for Saving, Include tablename and tablekey columnname here.
|
|
*/
|
|
public $tab_name_index = Array(
|
|
'vte_crmentity' => 'crmid',
|
|
'vte_charts' => 'chartid',
|
|
'vte_chartscf' => 'chartid',
|
|
'vte_chartscache' => 'chartid');
|
|
|
|
/**
|
|
* Mandatory for Listing (Related listview)
|
|
*/
|
|
public $list_fields = Array (
|
|
/* Format: Field Label => Array(tablename, columnname) */
|
|
// tablename should not have prefix 'vte_'
|
|
'Chart Name'=> Array('charts', 'chartname'),
|
|
'Assigned To' => Array('crmentity','smownerid')
|
|
);
|
|
|
|
public $list_fields_name = Array(
|
|
/* Format: Field Label => fieldname */
|
|
'Chart Name'=> 'chartname',
|
|
'Assigned To' => 'assigned_user_id'
|
|
);
|
|
|
|
// Make the field link to detail view from list view (Fieldname)
|
|
public $list_link_field = 'chartname';
|
|
|
|
// For Popup listview and UI type support
|
|
public $search_fields = Array(
|
|
/* Format: Field Label => Array(tablename, columnname) */
|
|
// tablename should not have prefix 'vte_'
|
|
'Chart Name'=> Array('charts', 'chartname')
|
|
);
|
|
|
|
public $search_fields_name = Array(
|
|
/* Format: Field Label => fieldname */
|
|
'Chart Name'=> 'chartname'
|
|
);
|
|
|
|
// For Popup window record selection
|
|
public $popup_fields = Array('chartname');
|
|
|
|
// Placeholder for sort fields - All the fields will be initialized for Sorting through initSortFields
|
|
public $sortby_fields = Array();
|
|
|
|
// For Alphabetical search
|
|
public $def_basicsearch_col = 'chartname';
|
|
|
|
// Column value to use on detail view record text display
|
|
public $def_detailview_recname = 'chartname';
|
|
|
|
// Required Information for enabling Import feature
|
|
public $required_fields = Array('chartname'=>1);
|
|
|
|
public $default_order_by = 'chartname';
|
|
public $default_sort_order='ASC';
|
|
// Used when enabling/disabling the mandatory fields for the module.
|
|
// Refers to vte_field.fieldname values.
|
|
public $mandatory_fields = Array('createdtime', 'modifiedtime', 'chartname');
|
|
//crmv@10759
|
|
public $search_base_field = 'chartname';
|
|
//crmv@10759 e
|
|
|
|
|
|
public $chartLibrary = 'ChartJS'; // can be pChart or ChartJS. pChart is currently deprecated and will be removed in the future
|
|
public $cachedir = 'cache/charts/';
|
|
public $cachefile_date = null;
|
|
public $image_size_x = 512;
|
|
public $image_size_y = 384;
|
|
public $graph_size_ratio = 3.2; // pie radius (=imagesize/ratio)
|
|
public $thumbnail_size = 160;
|
|
public $limit_data = 50; // in caso non si usi il merge, limito i dati
|
|
public $filtered_data = false; // prende i dati dalle tabelle con i dati filtrati // crmv@31209
|
|
public $label_split = 12; // split labels longer than 20chars // crmv@30976
|
|
public $merge_threshold = 3; // percentuale al di sotto della quale accorpare gli spicchi piccoli
|
|
public $homestuffid = null;
|
|
public $cachefield = 'chart_filename';
|
|
|
|
public $cache_duration = 24; // crmv@134727 - cache duration, in hours (for new js charts)
|
|
|
|
public $default_options = array(
|
|
// general options
|
|
'Main' => array(
|
|
'TitleHeight' => 0, // altezza della barra del titolo // TODO: remove me
|
|
'Padding' => 0, //
|
|
'PaddingLeft' => 0, // This padding is added only to the left
|
|
'PaddingBottom' => 0, // This padding is added only at the bottom
|
|
'GraphShadow' => true,
|
|
'ShowLegend' => false,
|
|
'StretchPalette' => false, // stretch palette to fit the number of values
|
|
),
|
|
|
|
'Scale' => array(
|
|
'ScaleSpacing' => 1,
|
|
),
|
|
|
|
'Legend' => array(
|
|
'Mode' => LEGEND_VERTICAL,
|
|
'Style' => LEGEND_ROUND,
|
|
'R' => 0xE0, 'G' => 0xE0, 'B' => 0xE0, "Alpha" => 80,
|
|
'BorderR' => 0xD0, 'BorderG' => 0xD0, 'BorderB' => 0xD0,
|
|
'FontName' => 'include/pChart/fonts/MYRIADPRO-REGULAR.OTF',
|
|
'FontSize' => 10,
|
|
//'Family' => LEGEND_FAMILY_CIRCLE,
|
|
'Position' => TEXT_ALIGN_TOPLEFT, // not a Pchart option!!, valid values: same as drawText format, only starting with LEFT
|
|
),
|
|
|
|
// specific options for graph types
|
|
'BarVertical' => array(
|
|
'DisplayOrientation' => ORIENTATION_VERTICAL,
|
|
'DisplayValues' => TRUE,
|
|
'Rounded' => TRUE,
|
|
'Surrounding' => -20,
|
|
'DisplayPos' => LABEL_POS_OUTSIDE,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE,
|
|
//'Gradient' => TRUE, // only if rounded false
|
|
),
|
|
'BarHorizontal' => array(
|
|
'DisplayOrientation' => ORIENTATION_HORIZONTAL,
|
|
'DisplayValues' => TRUE,
|
|
'Rounded' => TRUE,
|
|
'Surrounding' => -20,
|
|
'RecordImageMap' => TRUE,
|
|
'DisplayPos' => LABEL_POS_OUTSIDE,
|
|
'CyclePalette' => TRUE,
|
|
),
|
|
'Line' => array(
|
|
'LineWeight' => 1, // not a pChart option // crmv@53923
|
|
'DisplayValues' => TRUE,
|
|
'RecordImageMap' => TRUE,
|
|
),
|
|
'Pie' => array(
|
|
'DrawLabels'=>TRUE,
|
|
'DrawLabelLine' => FALSE,
|
|
'DrawLabelArrow' => TRUE,
|
|
'LabelDistance' => 20,
|
|
'LabelArrowSize' => 6,
|
|
'SecondPass' => TRUE,
|
|
'WriteValues' => FALSE,
|
|
'ValueR' => 0x40, 'ValueG' => 0x40, 'ValueB' => 0x40,
|
|
'Border' => TRUE,
|
|
'BorderR' => 0xF0, 'BorderG' => 0xF0, 'BorderB' => 0xF0,
|
|
//'LabelStacked' => TRUE,
|
|
'LabelColor' => PIE_LABEL_COLOR_MANUAL,
|
|
'LabelR' => 0x70, 'LabelG' => 0x70, 'LabelB' => 0x70,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE, // if false, use random colors
|
|
),
|
|
// DEPRECATED
|
|
/*'Pie3D' => array(
|
|
'DrawLabels'=>TRUE,
|
|
'DrawLabelLine' => FALSE,
|
|
'DrawLabelArrow' => TRUE,
|
|
'LabelDistance' => 20,
|
|
'LabelArrowSize' => 6,
|
|
//'LabelStacked' => TRUE,
|
|
'LabelColor' => PIE_LABEL_COLOR_MANUAL,
|
|
'LabelR' => 0x40, 'LabelG' => 0x40, 'LabelB' => 0x40,
|
|
'SecondPass' => TRUE,
|
|
'WriteValues' => FALSE,
|
|
'ValueR' => 0x40, 'ValueG' => 0x40, 'ValueB' => 0x40,
|
|
//'ValuePadding' => 0,
|
|
'Border' => TRUE,
|
|
'BorderR' => 0xD0, 'BorderG' => 0xD0, 'BorderB' => 0xD0,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE,
|
|
),
|
|
*/
|
|
'Ring' => array(
|
|
'DrawLabels'=>TRUE,
|
|
'DrawLabelLine' => FALSE,
|
|
'DrawLabelArrow' => TRUE,
|
|
'LabelDistance' => 20,
|
|
'LabelArrowSize' => 6,
|
|
'LabelColor' => PIE_LABEL_COLOR_MANUAL,
|
|
'LabelR' => 0x70, 'LabelG' => 0x70, 'LabelB' => 0x70,
|
|
'WriteValues' => FALSE,
|
|
'ValueR' => 0x40, 'ValueG' => 0x40, 'ValueB' => 0x40,
|
|
'Border' => TRUE,
|
|
'BorderR' => 0xD0, 'BorderG' => 0xD0, 'BorderB' => 0xD0,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE,
|
|
),
|
|
// DEPRECATED
|
|
/*
|
|
'Ring3D' => array(
|
|
'DrawLabels'=>TRUE,
|
|
'DrawLabelLine' => FALSE,
|
|
'DrawLabelArrow' => TRUE,
|
|
'LabelDistance' => 20,
|
|
'LabelArrowSize' => 6,
|
|
'LabelColor' => PIE_LABEL_COLOR_MANUAL,
|
|
'LabelR' => 0x40, 'LabelG' => 0x40, 'LabelB' => 0x40,
|
|
'WriteValues' => FALSE,
|
|
'ValueR' => 0x40, 'ValueG' => 0x40, 'ValueB' => 0x40,
|
|
'DataGapAngle' => 0,
|
|
'DataGapRadius' => 0,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE,
|
|
),
|
|
*/
|
|
'Split' => array(
|
|
'TextPos' => TEXT_POS_RIGHT,
|
|
'TextPadding'=>10,
|
|
'Spacing'=>20,
|
|
'Surrounding'=>40,
|
|
'RecordImageMap' => TRUE,
|
|
'CyclePalette' => TRUE,
|
|
),
|
|
// crmv@53923
|
|
'Scatter' => array(
|
|
)
|
|
// crmv@53923e
|
|
|
|
);
|
|
|
|
public $default_options_js = array(
|
|
// general options
|
|
'Main' => array(
|
|
'chartjs' => array(
|
|
'animation' => true,
|
|
'tooltipFontSize' => 12,
|
|
'legend' => false,
|
|
//'tooltipTemplate' => "<%if (label){%><%=label%>: <%}%><%= value %> (<%= Math.round(circumference / 6.283 * 100) %>%)", // TODO: find out how to put the percentage
|
|
|
|
),
|
|
),
|
|
'BarVertical' => array(
|
|
'chartjs' => array(
|
|
'barStrokeWidth' => 1,
|
|
// legend is disabled for bars,since there is only one serie
|
|
//'legendTemplate' => "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span class=\"legend-box\" style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
|
'tooltipTemplate' => "<%=label%>###<%=value%>", // this is handled by javascript
|
|
),
|
|
),
|
|
'BarHorizontal' => array(
|
|
'chartjs' => array(
|
|
'barStrokeWidth' => 1,
|
|
//'legendTemplate' => "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span class=\"legend-box\" style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
|
'tooltipTemplate' => "<%=label%>###<%=value%>", // this is handled by javascript
|
|
),
|
|
),
|
|
'Pie' => array(
|
|
'chartjs' => array(
|
|
'legendTemplate' => "<span class=\"legend-title hidden\"></span><ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span class=\"legend-box\" style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
|
'tooltipTemplate' => "<%if (label){%><%=label%>: <%}%><%= formatUserNumber(value) %> (<%= Math.round(circumference / 6.283 * 100) %>%)",
|
|
),
|
|
),
|
|
'Ring' => array(
|
|
'chartjs' => array(
|
|
'legendTemplate' => "<span class=\"legend-title hidden\"></span><ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span class=\"legend-box\" style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
|
'tooltipTemplate' => "<%if (label){%><%=label%>: <%}%><%= formatUserNumber(value) %> (<%= Math.round(circumference / 6.283 * 100) %>%)",
|
|
),
|
|
),
|
|
'Line' => array(
|
|
'chartjs' => array(
|
|
'tooltipTemplate' => "<%=label%>###<%=value%>", // this is handled by javascript
|
|
),
|
|
),
|
|
);
|
|
|
|
function __construct() {
|
|
global $log, $table_prefix; // crmv@97862
|
|
parent::__construct(); // crmv@37004
|
|
|
|
$this->column_fields = getColumnFields('Charts'); // crmv@97862
|
|
$this->db = PearDatabase::getInstance();
|
|
$this->log = $log;
|
|
|
|
$this->table_name = $table_prefix.'_charts';
|
|
$this->customFieldTable = Array($table_prefix.'_chartscf', 'chartid');
|
|
$this->tab_name = Array($table_prefix.'_crmentity', $table_prefix.'_charts', $table_prefix.'_chartscf', $table_prefix.'_chartscache');
|
|
$this->tab_name_index = Array(
|
|
$table_prefix.'_crmentity' => 'crmid',
|
|
$table_prefix.'_charts' => 'chartid',
|
|
$table_prefix.'_chartscf' => 'chartid',
|
|
$table_prefix.'_chartscache' => 'chartid',
|
|
);
|
|
|
|
}
|
|
|
|
|
|
function save_module($module) {
|
|
global $adb;
|
|
|
|
// invalidate filename
|
|
$this->invalidateCache();
|
|
}
|
|
|
|
// crmv@113417
|
|
function retrieve_entity_info($recordid, $module, $dieOnError=true, $onlyFields = array()) {
|
|
$ret = parent::retrieve_entity_info($recordid, $module, $dieOnError, $onlyFields);
|
|
|
|
// get cache file date
|
|
$fname = $this->column_fields[$this->cachefield];
|
|
$this->cachefile_date[$this->cachefield] = null;
|
|
if (!empty($fname) && is_readable($fname)) {
|
|
$this->cachefile_date[$this->cachefield] = filemtime($fname);
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
// crmv@113417e
|
|
|
|
/**
|
|
* Return query to use based on given modulename, fieldname
|
|
* Useful to handle specific case handling for Popup
|
|
*/
|
|
function getQueryByModuleField($module, $fieldname, $srcrecord) {
|
|
// $srcrecord could be empty
|
|
}
|
|
|
|
function getQueryExtraJoin() {
|
|
global $table_prefix;
|
|
return "LEFT JOIN {$table_prefix}_report ON {$table_prefix}_charts.reportid = {$table_prefix}_report.reportid";
|
|
}
|
|
|
|
function getQueryExtraWhere() {
|
|
global $table_prefix, $current_user;
|
|
|
|
$repquery = '';
|
|
if ($current_user->is_admin != 'on') {
|
|
$userGroups = new GetUserGroups();
|
|
$userGroups->getAllUserGroups($current_user->id);
|
|
$user_groups = $userGroups->user_groups;
|
|
|
|
$groupquery = '';
|
|
if (!empty($user_groups)) {
|
|
$groupquery = "OR (setype = 'groups' AND shareid in (".implode(',', $user_groups)."))";
|
|
}
|
|
|
|
// crmv@144121
|
|
$repquery = " AND (
|
|
({$table_prefix}_report.sharingtype = 'Public') OR
|
|
({$table_prefix}_report.owner = '{$current_user->id}') OR
|
|
({$table_prefix}_report.sharingtype = 'Shared' AND EXISTS (
|
|
SELECT reportid FROM {$table_prefix}_reportsharing WHERE reportid = {$table_prefix}_charts.reportid AND ((setype = 'users' AND shareid = '{$current_user->id}') $groupquery)
|
|
))
|
|
)";
|
|
// crmv@144121e
|
|
}
|
|
|
|
// crmv@30967
|
|
$fldid = intval($_REQUEST['folderid']);
|
|
if ($fldid > 0) $repquery .= " and {$this->table_name}.folderid = '$fldid'";
|
|
// crmv@30967e
|
|
|
|
return $repquery;
|
|
}
|
|
|
|
// set the field that holds the filename of the cached file
|
|
function setCacheField($fieldcache = 'chart_filename') {
|
|
if (!empty($fieldcache)) {
|
|
$this->cachefield = $fieldcache;
|
|
$fname = $this->column_fields[$this->cachefield];
|
|
if (!empty($fname) && is_readable($fname)) {
|
|
$this->cachefile_date[$this->cachefield] = filemtime($fname);
|
|
}
|
|
}
|
|
}
|
|
|
|
// genera il nome del file in cui scrivere il grafico
|
|
function generateFileName($format = 'png') {
|
|
|
|
|
|
if (!is_dir($this->cachedir)) {
|
|
@mkdir($this->cachedir, 0755, true);
|
|
}
|
|
|
|
if (!is_writable($this->cachedir)) {
|
|
//throw new Exception("Directory $basedir is not writable.");
|
|
return null;
|
|
}
|
|
|
|
$randval = uniqid().mt_rand(0, 1000);
|
|
|
|
return $this->cachedir."chart_{$randval}.$format";
|
|
}
|
|
|
|
function initGraphOptions(&$DataSet) {
|
|
if ($this->chartLibrary == 'pChart') {
|
|
return $this->initGraphOptionsPChart($DataSet);
|
|
} elseif ($this->chartLibrary == 'ChartJS') {
|
|
return $this->initGraphOptionsChartJS($DataSet);
|
|
}
|
|
}
|
|
|
|
function initGraphOptionsChartJS(&$rawdata) {
|
|
$type = $this->column_fields['chart_type'];
|
|
if (empty($type)) return null;
|
|
|
|
if ($this->column_fields['chart_legend'] == 1) {
|
|
if ($type == 'Pie' || $type == 'Ring') {
|
|
$this->default_options_js['Main']['chartjs']['legend'] = true;
|
|
}
|
|
}
|
|
|
|
if ($this->column_fields['chart_values'] != 'ChartValuesNone') {
|
|
if ($type == 'Pie' || $type == 'Ring') {
|
|
$this->default_options_js['Main']['chartjs']['drawLabels'] = true;
|
|
$this->default_options_js['Main']['chartjs']['labelType'] = $this->column_fields['chart_values'];
|
|
}
|
|
}
|
|
|
|
if ($this->column_fields['chart_labels'] == 1) {
|
|
if ($type == 'Pie' || $type == 'Ring') {
|
|
$this->default_options_js['Main']['chartjs']['drawLabels'] = true;
|
|
$this->default_options_js['Main']['chartjs']['labelType'] = 'ChartLabels';
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// change default options according to the graph type
|
|
function initGraphOptionsPChart(&$DataSet) { // crmv@53923
|
|
|
|
$type = $this->column_fields['chart_type'];
|
|
if (empty($type)) return null;
|
|
$explode = $this->column_fields['chart_exploded'];
|
|
$dataMin = $DataSet->getMin('Serie1'); // crmv@41431
|
|
$dataMax = $DataSet->getMax('Serie1'); //crmv@73193
|
|
switch ($type) {
|
|
case 'BarVertical':
|
|
$this->default_options['Scale']['Pos'] = SCALE_POS_LEFTRIGHT;
|
|
//crmv@73193
|
|
//if ($dataMin >= 0) $this->default_options['Scale']['Mode'] = SCALE_MODE_START0; // crmv@41431
|
|
if ($dataMin >= 0){
|
|
$this->default_options['Scale']['Mode'] = SCALE_MODE_MANUAL;
|
|
$min = 0;
|
|
$max = round((floatval($dataMax)*110/100),0, PHP_ROUND_HALF_UP); //add 10% to max value to avoid cutting labels
|
|
$AxisBoundaries = array(0=>array("Min"=>$min,"Max"=>$max));
|
|
$this->default_options['Scale']['ManualScale']=$AxisBoundaries;
|
|
}
|
|
//crmv@73193e
|
|
$this->default_options[$type]['OverrideColors'] = $DataSet->getPalette();
|
|
// crmv@53923 - calculate the bottom padding
|
|
$values = $DataSet->getValues('Labels');
|
|
if (is_array($values)) {
|
|
$maxNewLine = 0;
|
|
foreach ($values as $v) {
|
|
$c = substr_count($v, "\n");
|
|
if ($c > $maxNewLine) $maxNewLine = $c;
|
|
}
|
|
$this->default_options['Main']["PaddingBottom"] = 18*($maxNewLine+1);
|
|
}
|
|
// crmv@53923e
|
|
break;
|
|
case 'BarHorizontal':
|
|
$this->default_options['Scale']['Pos'] = SCALE_POS_TOPBOTTOM;
|
|
if ($dataMin >= 0) $this->default_options['Scale']['Mode'] = SCALE_MODE_START0; // crmv@41431
|
|
$this->default_options[$type]['OverrideColors'] = $DataSet->getPalette();
|
|
$this->default_options['Main']["PaddingLeft"] = 80;
|
|
break;
|
|
case 'Line':
|
|
// crmv@53923
|
|
$dataMax = $DataSet->getMax('Serie1');
|
|
$dataMaxLen = strlen(strval(intval($dataMax)));
|
|
$this->default_options['Scale']["DrawSubTicks"] = TRUE;
|
|
$this->default_options['Main']["Padding"] = 20;
|
|
$this->default_options['Main']["PaddingLeft"] = 5*$dataMaxLen;
|
|
// crmv@53923e
|
|
break;
|
|
case 'Pie':
|
|
$this->default_options[$type]['Radius'] = min($this->image_size_x, $this->image_size_y)/$this->graph_size_ratio;
|
|
if ($explode) {
|
|
$this->default_options[$type]['DataGapAngle'] = 8;
|
|
$this->default_options[$type]['DataGapRadius'] = 10;
|
|
}
|
|
break;
|
|
// DEPRECATED
|
|
/*case 'Pie3D':
|
|
$this->default_options[$type]['Radius'] = min($this->image_size_x, $this->image_size_y)/$this->graph_size_ratio;
|
|
if ($explode) {
|
|
$this->default_options[$type]['DataGapAngle'] = 8;
|
|
$this->default_options[$type]['DataGapRadius'] = 10;
|
|
}
|
|
break;
|
|
*/
|
|
case 'Ring':
|
|
$this->default_options[$type]['InnerRadius'] = min($this->image_size_x, $this->image_size_y)/(2*$this->graph_size_ratio);
|
|
$this->default_options[$type]['OuterRadius'] = min($this->image_size_x, $this->image_size_y)/$this->graph_size_ratio;
|
|
if ($explode) {
|
|
$this->default_options[$type]['DataGapAngle'] = 8;
|
|
$this->default_options[$type]['DataGapRadius'] = 10;
|
|
}
|
|
break;
|
|
// DEPRECATED
|
|
/*case 'Ring3D':
|
|
$this->default_options[$type]['InnerRadius'] = min($this->image_size_x, $this->image_size_y)/(2*$this->graph_size_ratio);
|
|
$this->default_options[$type]['OuterRadius'] = min($this->image_size_x, $this->image_size_y)/$this->graph_size_ratio;
|
|
if ($explode) {
|
|
$this->default_options[$type]['DataGapAngle'] = 8;
|
|
$this->default_options[$type]['DataGapRadius'] = 10;
|
|
}
|
|
break;
|
|
*/
|
|
// DEPRECATED
|
|
/*case 'Split':
|
|
$this->default_options['Main']['GraphShadow']= false;
|
|
break;
|
|
*/
|
|
// crmv@53923 - EXPERIMENTAL
|
|
case 'Scatter':
|
|
$DataSet->setAxisXY(0,AXIS_X);
|
|
$DataSet->setAxisPosition(0,AXIS_POSITION_BOTTOM);
|
|
$DataSet->setSerieOnAxis("Serie1",1);
|
|
$DataSet->setAxisXY(1,AXIS_Y);
|
|
$DataSet->setAxisPosition(1,AXIS_POSITION_LEFT);
|
|
$DataSet->setScatterSerie('Labels', 'Serie1', 0);
|
|
$dataMax = $DataSet->getMax('Serie1');
|
|
$dataMaxLen = strlen(strval(intval($dataMax)));
|
|
$this->default_options['Main']["Padding"] = 20;
|
|
$this->default_options['Main']["PaddingLeft"] = 5*$dataMaxLen;
|
|
break;
|
|
// crmv@53923e
|
|
}
|
|
|
|
if ($this->column_fields['chart_legend'] == 1) {
|
|
$this->default_options['Main']['ShowLegend'] = true;
|
|
}
|
|
|
|
if ($this->column_fields['chart_labels'] == 0) {
|
|
$this->default_options[$type]['DrawLabels'] = FALSE;
|
|
}
|
|
|
|
switch ($this->column_fields['chart_values']) {
|
|
case 'ChartValuesRaw':
|
|
$this->default_options[$type]['WriteValues'] = PIE_VALUE_NATURAL;
|
|
$this->default_options[$type]['ValuePosition'] = PIE_VALUE_INSIDE;
|
|
break;
|
|
case 'ChartValuesPercent':
|
|
$this->default_options[$type]['WriteValues'] = PIE_VALUE_PERCENTAGE;
|
|
$this->default_options[$type]['ValuePosition'] = PIE_VALUE_INSIDE;
|
|
break;
|
|
case 'ChartValuesNone':
|
|
default:
|
|
$this->default_options[$type]['WriteValues'] = FALSE;
|
|
$this->default_options[$type]['ValuePosition'] = PIE_VALUE_INSIDE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected function getValueColumn($level = 1) {
|
|
// crmv@30976
|
|
$formula = $this->column_fields['chart_formula'];
|
|
switch ($formula) {
|
|
default:
|
|
case 'COUNT':
|
|
$formulacol = "count_liv{$level}";
|
|
break;
|
|
case 'SUM':
|
|
$formulacol = "formula{$level}_sum";
|
|
break;
|
|
case 'AVG':
|
|
$formulacol = "formula{$level}_avg";
|
|
break;
|
|
case 'MIN':
|
|
$formulacol = "formula{$level}_min";
|
|
break;
|
|
case 'MAX':
|
|
$formulacol = "formula{$level}_max";
|
|
break;
|
|
}
|
|
// crmv@30976e
|
|
return $formulacol;
|
|
}
|
|
|
|
// recupera i dati per disegnare il grafico
|
|
function getChartData($level = 1, $levelIds = array()) {
|
|
global $adb, $table_prefix, $current_user; // crmv@97862
|
|
|
|
$level = intval($level) ?: 1;
|
|
$ret = array();
|
|
|
|
$reportid = $this->column_fields['reportid'];
|
|
if (empty($reportid)) return null;
|
|
|
|
$formulacol = $this->getValueColumn($level);
|
|
|
|
// crmv@31209 crmv@185894
|
|
$oReportRun = ReportRun::getInstance($reportid);
|
|
$oReportRun->enableCacheDb();
|
|
$datatable_master = $datatable = $oReportRun->getLivTable('levels');
|
|
if ($this->filtered_data) $datatable = $oReportRun->getLivTable('liv',$level);
|
|
// crmv@31209e crmv@185894e
|
|
|
|
// TODO: controlla se report ha i conteggi
|
|
// TODO: limite di dati presi
|
|
// TODO: check query for Oracle and MsSQL
|
|
|
|
// crmv@104070 crmv@186088
|
|
// basic check to see if there are rows
|
|
if (!$this->filtered_data) {
|
|
$res = $adb->limitPquerySlave('Reports',"select reportid FROM {$datatable_master} where reportid = ? and userid = ?", 0, 1, array($reportid, $current_user->id)); // crmv@185894
|
|
if ($res && $adb->num_rows($res) == 0) {
|
|
// no rows, maybe it has never run!
|
|
$this->reloadReport();
|
|
}
|
|
}
|
|
// crmv@104070e crmv@186088e
|
|
|
|
// crmv@134727
|
|
// info generali sul report
|
|
$res = $adb->pquerySlave('Reports', // crmv@185894
|
|
"SELECT r.reportname, rs.generatedtime
|
|
FROM {$table_prefix}_report r
|
|
LEFT JOIN {$table_prefix}_report_stats rs ON rs.reportid = r.reportid AND rs.userid = ?
|
|
WHERE r.reportid = ?",
|
|
array($current_user->id, $reportid)
|
|
);
|
|
if ($res) {
|
|
$ret['reportname'] = $adb->query_result_no_html($res, 0, 'reportname');
|
|
$this->chart_title = $ret['reportname'] . (empty($this->column_fields['chartname']) ? '' : (' - '.$this->column_fields['chartname']) );
|
|
$ret['generatedtime'] = $adb->query_result_no_html($res, 0, 'generatedtime');
|
|
}
|
|
|
|
// crmv@172355
|
|
// check if report has summary, but allow sdk reports
|
|
$oReportRun = $this->getReportRunObj();
|
|
if ($oReportRun instanceof ReportRun && !$oReportRun->hasSummary()) return 'NO_SUMMARY';
|
|
// crmv@172355e
|
|
|
|
// regenerate if too old
|
|
$cacheDate = time() - $this->cache_duration*3600;
|
|
if (empty($ret['generatedtime']) || strtotime($ret['generatedtime']) < $cacheDate) {
|
|
$this->reloadReport();
|
|
$ret['generatedtime'] = date('Y-m-d H:i:s');
|
|
}
|
|
// crmv@134727e
|
|
|
|
$params = array($reportid, $current_user->id); // crmv@97862
|
|
$subwhere = '';
|
|
|
|
// conditions for sub levels
|
|
if ($level > 1 && is_array($levelIds) && count($levelIds) > 0) {
|
|
$i = 0;
|
|
$levelIds = array_values($levelIds);
|
|
for ($slevel=1; $slevel<$level; ++$slevel) {
|
|
$levelid = $levelIds[$i++];
|
|
$subwhere .= " AND id_liv{$slevel} = ?";
|
|
$params[] = $levelid;
|
|
}
|
|
}
|
|
|
|
// ordino per conteggio
|
|
if ($this->column_fields['chart_order_data'] == 'OrderAsc') {
|
|
$orderby = "ORDER BY val ASC"; // crmv@165801
|
|
} elseif ($this->column_fields['chart_order_data'] == 'OrderDesc') {
|
|
$orderby = "ORDER BY val DESC"; // crmv@165801
|
|
} else {
|
|
$orderby = '';
|
|
}
|
|
|
|
$colors = $this->getReportColors(); // crmv@133997
|
|
|
|
$total = 0;
|
|
$total_rows = 0;
|
|
// limito i valori nel caso non abbia il merge attivo
|
|
// crmv@185894
|
|
if ($this->column_fields['chart_merge_small']) {
|
|
$res = $adb->pquerySlave('Reports',"SELECT MAX(value_liv{$level}) AS valname, MAX($formulacol) AS val, id_liv{$level} AS dataid FROM $datatable WHERE reportid = ? AND userid = ? $subwhere GROUP BY id_liv{$level} ".$orderby, $params); // crmv@30976 crmv@31209 crmv@97862 crmv@165801
|
|
if ($res) $total_rows = $adb->num_rows($res);
|
|
} else {
|
|
$rescount = $adb->pquerySlave('Reports',"SELECT COUNT(*) as rcount FROM (SELECT id_liv{$level} FROM {$datatable} WHERE reportid = ? AND userid = ? $subwhere GROUP BY id_liv{$level}) tt", $params); // crmv@97862 crmv@192261
|
|
if ($rescount) $total_rows = $adb->query_result_no_html($rescount, 0, 'rcount');
|
|
unset($rescount);
|
|
$res = $adb->limitpQuerySlave('Reports',"SELECT MAX(value_liv{$level}) AS valname, MAX($formulacol) AS val, id_liv{$level} AS dataid FROM $datatable WHERE reportid = ? AND userid = ? $subwhere GROUP BY id_liv{$level} ".$orderby, 0, $this->limit_data, $params); // crmv@30976 crmv@31209 crmv@97862 crmv@165801
|
|
}
|
|
// crmv@185894e
|
|
|
|
if ($res) {
|
|
// crmv@109353
|
|
while ($row = $adb->FetchByAssoc($res, -1, false)) {
|
|
$value = $row['val'];
|
|
$label = $row['valname'];
|
|
// check/convert date fields
|
|
if (trim($label) === '') {
|
|
$label = getTranslatedString('LBL_EMPTY_LABEL', 'Charts');
|
|
} elseif (preg_match('/^[12][0-9]{3}-[01][0-9]-[0123][0-9]$/', $label)) {
|
|
$label = getDisplayDate($label);
|
|
}
|
|
// crmv@30976
|
|
if ($this->label_split > 0) {
|
|
$label = wordwrap($label, $this->label_split);
|
|
}
|
|
// crmv@30976e
|
|
$ret['values'][] = $value;
|
|
$ret['labels'][] = decode_html($label); //crmv@123493
|
|
$ret['dataids'][] = $row['dataid'];
|
|
// crmv@133997
|
|
if ($level == 1 && !empty($colors)) {
|
|
$color = $colors[$row['valname']];
|
|
$ret['colors'][] = $color;
|
|
}
|
|
// crmv@133997e
|
|
$total += $value;
|
|
}
|
|
// crmv@109353e
|
|
}
|
|
|
|
// controllo se ho limitato i risultati
|
|
$ret['limited'] = ($total_rows != count($ret['values']));
|
|
|
|
$this->mergeSmallData($ret, $total);
|
|
|
|
if (is_array($ret['values'])) $ret['values'] = array_values($ret['values']);
|
|
if (is_array($ret['labels'])) $ret['labels'] = array_values($ret['labels']);
|
|
if (is_array($ret['dataids'])) $ret['dataids'] = array_values($ret['dataids']);
|
|
|
|
return $ret;
|
|
}
|
|
|
|
public function getLevelIdsValues($levelIds) { // crmv@99131
|
|
global $adb;
|
|
|
|
$values = array();
|
|
|
|
$level = count($levelIds)+1;
|
|
$reportid = $this->column_fields['reportid'];
|
|
// crmv@185894
|
|
$oReportRun = ReportRun::getInstance($reportid);
|
|
$oReportRun->enableCacheDb();
|
|
// crmv@185894e
|
|
$formulacol = $this->getValueColumn($level);
|
|
|
|
$params = array($reportid);
|
|
$subwhere = '';
|
|
if ($level > 1) {
|
|
$i = 0;
|
|
$levelIds = array_values($levelIds);
|
|
for ($slevel=1; $slevel<$level; ++$slevel) {
|
|
$levelid = $levelIds[$i++];
|
|
$subwhere .= " AND id_liv{$slevel} = ?";
|
|
$params[] = $levelid;
|
|
}
|
|
$res = $adb->limitpQuerySlave('Reports',"SELECT * FROM ".$oReportRun->getLivTable('levels')." WHERE reportid = ? $subwhere ", 0, 1, $params); // crmv@30976 crmv@31209 crmv@185894
|
|
if ($res) {
|
|
$row = $adb->FetchByAssoc($res, -1, false);
|
|
for ($slevel=1; $slevel<$level; ++$slevel) {
|
|
$levelid = $row['id_liv'.$slevel];
|
|
$values[$levelid] = array(
|
|
'dataid' => $levelid,
|
|
'label' => trim($row['value_liv'.$slevel]) ?: getTranslatedString('LBL_EMPTY_LABEL', 'Charts'),
|
|
'count' => $row['count_liv'.$slevel],
|
|
'value' => $row[$formulacol],
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
return $values;
|
|
}
|
|
|
|
public function getMaxLevels() { // crmv@99131
|
|
global $adb, $current_user;
|
|
|
|
$levels = 0;
|
|
$reportid = $this->column_fields['reportid'];
|
|
// crmv@185894
|
|
$oReportRun = ReportRun::getInstance($reportid);
|
|
$oReportRun->enableCacheDb();
|
|
$res = $adb->limitpQuerySlave('Reports',"SELECT * FROM ".$oReportRun->getLivTable('levels')." WHERE reportid = ? AND userid = ?", 0, 1, array($reportid, $current_user->id)); // crmv@143801
|
|
// crmv@185894e
|
|
if ($res) {
|
|
$row = $adb->FetchByAssoc($res, -1, false);
|
|
for ($i=1; $i<=7; ++$i) {
|
|
if (isset($row['id_liv'.$i]) && $row['id_liv'.$i] > 0) {
|
|
++$levels;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return $levels;
|
|
}
|
|
|
|
// crmv@99131
|
|
public function getLevelTitles() { // crmv@99131
|
|
global $adb, $table_prefix;
|
|
|
|
$names = array();
|
|
$reportid = $this->column_fields['reportid'];
|
|
$reports = Reports::getInstance();
|
|
$fields = $reports->getColumns($reportid);
|
|
foreach ($fields as $field) {
|
|
if ($field['group'] == 1 && $field['fieldid'] > 0) {
|
|
$finfo = $reports->getFieldInfoById($field['fieldid']);
|
|
if ($finfo['label']) {
|
|
$names[] = $finfo['label'];
|
|
} else {
|
|
$names[] = getTranslatedString($finfo['fieldlabel'], $finfo['module']);
|
|
}
|
|
}
|
|
}
|
|
return $names;
|
|
}
|
|
// crmv@99131e
|
|
|
|
// unisce i dati troppo piccoli
|
|
protected function mergeSmallData(&$ret, $valuetotal) {
|
|
// unisco gli spicchi piccoli (sommo i valori che sono < del 3%)
|
|
if ($valuetotal > 0 && $this->column_fields['chart_merge_small']) {
|
|
$replace_pos = null;
|
|
$replace_val = 0;
|
|
$remove_data = array();
|
|
$i = 0;
|
|
foreach ($ret['values'] as $v) {
|
|
$vpercent = 100.0*$v/$valuetotal;
|
|
if ($vpercent < $this->merge_threshold) {
|
|
$replace_val += $v;
|
|
if (is_null($replace_pos)) {
|
|
$replace_pos = $i;
|
|
} else {
|
|
$remove_data[] = $i;
|
|
}
|
|
}
|
|
++$i;
|
|
}
|
|
if (!is_null($replace_pos) && count($remove_data) > 0) {
|
|
$remove_data = array_reverse($remove_data);
|
|
foreach ($remove_data as $rpos) {
|
|
unset($ret['values'][$rpos]);
|
|
unset($ret['labels'][$rpos]);
|
|
unset($ret['dataids'][$rpos]);
|
|
}
|
|
$ret['values'][$replace_pos] = $replace_val;
|
|
$ret['labels'][$replace_pos] = getTranslatedString('LBL_OTHERS_LABEL', 'Charts')." (".strval(count($remove_data)+1).")";
|
|
$ret['dataids'][$replace_pos] = -1;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// restituisce un set di dati per le anteprime
|
|
function getChartDemoData() {
|
|
|
|
$this->chart_title = 'test';
|
|
|
|
$ret = array();
|
|
$ret['values'] = array(5, 7,12, 1,17, 9,27,13,52, 48, 22);
|
|
$ret['labels'] = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
|
|
$ret['dataids'] = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
|
|
|
|
$total = array_sum($ret['values']);
|
|
|
|
$this->mergeSmallData($ret, $total);
|
|
|
|
if ($this->column_fields['chart_order_data'] == 'OrderAsc') {
|
|
$vlist = array_combine($ret['labels'], $ret['values']);
|
|
asort($vlist);
|
|
$ret['values'] = array_values($vlist);
|
|
$ret['labels'] = array_keys($vlist);
|
|
} elseif ($this->column_fields['chart_order_data'] == 'OrderDesc') {
|
|
$vlist = array_combine($ret['labels'], $ret['values']);
|
|
arsort($vlist);
|
|
$ret['values'] = array_values($vlist);
|
|
$ret['labels'] = array_keys($vlist);
|
|
} else {
|
|
// no sorting
|
|
}
|
|
|
|
$ret['values'] = array_values($ret['values']);
|
|
$ret['labels'] = array_values($ret['labels']);
|
|
$ret['dataids'] = array_values($ret['dataids']);
|
|
|
|
return $ret;
|
|
}
|
|
|
|
function getChartTitle() {
|
|
if (empty($this->chart_title)) {
|
|
$this->getChartData();
|
|
}
|
|
return $this->chart_title;
|
|
}
|
|
|
|
function generateChart($usedemodata = false, $level = 1, $levelIds = array()) {
|
|
if ($this->chartLibrary == 'pChart') {
|
|
return $this->generateChartPChart($usedemodata, $level, $levelIds);
|
|
} elseif ($this->chartLibrary == 'ChartJS') {
|
|
return $this->generateChartJS($usedemodata, $level, $levelIds);
|
|
}
|
|
}
|
|
|
|
function generateChartJS($usedemodata = false, $level = 1, $levelIds = array()) {
|
|
$type = $this->column_fields['chart_type'];
|
|
if (empty($type)) return null;
|
|
|
|
if ($usedemodata)
|
|
$rawdata = $this->getChartDemoData($level, $levelIds);
|
|
else
|
|
$rawdata = $this->getChartData($level, $levelIds);
|
|
if (empty($rawdata) || empty($rawdata['values'])) return null; // crmv@31209
|
|
if ($rawdata == 'NO_SUMMARY') return 'NO_SUMMARY'; // crmv@172355
|
|
|
|
// load palette
|
|
$palfile = $this->column_fields['chart_palette'];
|
|
if (empty($palfile) || !is_readable('modules/Charts/palettes/'.$palfile.'.color')) {
|
|
if (in_array($type, array('BarHorizontal', 'BarVertical', 'Line'))) {
|
|
$palfile = 'vtetheme';
|
|
} else {
|
|
$palfile = 'default';
|
|
}
|
|
}
|
|
$mainPalette = $this->parsePaletteFile("modules/Charts/palettes/$palfile.color");
|
|
$palette = $this->paletteRGB2Css($mainPalette);
|
|
$hpalette = $this->paletteRGB2Css($this->variatePalette($mainPalette, 'lighten', array('percentage'=>10)));
|
|
$spalette = $this->paletteRGB2Css($this->variatePalette($mainPalette, 'darken', array('percentage'=>10)));
|
|
$paletteCount = count($mainPalette);
|
|
|
|
// add some basic vars
|
|
$rawdata['type'] = $type;
|
|
$rawdata['canvas_width'] = $this->image_size_x;
|
|
$rawdata['canvas_height'] = $this->image_size_y;
|
|
|
|
$rawdata['level'] = $level;
|
|
$rawdata['levelids'] = $this->getLevelIdsValues($levelIds);
|
|
$rawdata['maxlevels'] = $this->getMaxLevels();
|
|
|
|
if ($rawdata['maxlevels'] > 1) {
|
|
$rawdata['leveltitles'] = $this->getLevelTitles();
|
|
}
|
|
|
|
// alter options and other variables
|
|
$this->initGraphOptions($rawdata);
|
|
|
|
// set chartjs options
|
|
$rawdata['options'] = $this->default_options_js['Main']['chartjs'] ?: array();
|
|
$rawdata['options'] = array_merge_recursive($rawdata['options'], $this->default_options_js[$type]['chartjs'] ?: array());
|
|
|
|
// reorder data
|
|
if (is_array($rawdata['values'])) {
|
|
$jsValues = array();
|
|
$count = count($rawdata['values']);
|
|
|
|
// crmv@133997
|
|
if ($rawdata['colors']) {
|
|
$colors = $rawdata['colors'];
|
|
$hcolors = $this->paletteRGB2Css($this->variatePalette($this->paletteCss2RGB($colors), 'lighten', array('percentage'=>10)));
|
|
$scolors = $this->paletteRGB2Css($this->variatePalette($this->paletteCss2RGB($colors), 'darken', array('percentage'=>10)));
|
|
}
|
|
// crmv@133997e
|
|
|
|
if ($type == 'Pie' || $type == 'Ring') {
|
|
foreach ($rawdata['values'] as $k=>$value) {
|
|
$jsValues[] = array(
|
|
'value' => $value,
|
|
'label' => $rawdata['labels'][$k],
|
|
'dataid' => $rawdata['dataids'][$k],
|
|
// crmv@133997
|
|
'color' => $colors[$k] ?: $palette[$k % $paletteCount],
|
|
'highlight' => $hcolors[$k] ?: $hpalette[$k % $paletteCount],
|
|
// crmv@133997e
|
|
);
|
|
}
|
|
|
|
} else {
|
|
$k = 0;
|
|
$jsValues['labels'] = $rawdata['labels'];
|
|
$jsValues['datasets'] = array();
|
|
$jsValues['datasets'][] = array(
|
|
'label' => 'Serie1',
|
|
'data' => $rawdata['values'],
|
|
'dataids' => $rawdata['dataids'],
|
|
// crmv@133997
|
|
'fillColor' => $colors ?: $palette[($type == 'Line' ? 1 : $k) % $paletteCount],
|
|
'strokeColor' => $scolors ?: $spalette[$k % $paletteCount],
|
|
'highlightFill' => $hcolors ?: $hpalette[$k % $paletteCount],
|
|
'highlightStroke' => $colors ?:$palette[$k % $paletteCount],
|
|
// crmv@133997e
|
|
);
|
|
}
|
|
unset($rawdata['labels']);
|
|
unset($rawdata['dataids']);
|
|
unset($rawdata['colors']); // crmv@133997
|
|
$rawdata['values'] = $jsValues;
|
|
} else {
|
|
unset($rawdata['labels']);
|
|
unset($rawdata['dataids']);
|
|
unset($rawdata['colors']); // crmv@133997
|
|
$rawdata['values'] = array();
|
|
}
|
|
|
|
return $rawdata;
|
|
}
|
|
|
|
// genera il grafico e restituisce il nome del file
|
|
function generateChartPChart($usedemodata = false, $level = 1, $levelIds = array()) {
|
|
global $adb, $table_prefix;
|
|
|
|
// reuse cached image
|
|
|
|
$fname = $this->column_fields[$this->cachefield];
|
|
if (!empty($fname) && is_readable($fname)) {
|
|
$this->map_file = preg_replace('/\.png/', '_map.map', $fname);
|
|
return $fname;
|
|
}
|
|
|
|
$fname = $this->generateFileName();
|
|
if (empty($fname)) return null;
|
|
|
|
$type = $this->column_fields['chart_type'];
|
|
if (empty($type)) return null;
|
|
|
|
if ($usedemodata)
|
|
$rawdata = $this->getChartDemoData($level, $levelIds);
|
|
else
|
|
$rawdata = $this->getChartData($level, $levelIds);
|
|
if (empty($rawdata) || empty($rawdata['values'])) return null; // crmv@31209
|
|
if ($rawdata == 'NO_SUMMARY') return 'NO_SUMMARY'; // crmv@172355
|
|
|
|
// dataset
|
|
$DataSet = new pData();
|
|
|
|
$DataSet->addPoints($rawdata['values'], 'Serie1');
|
|
$DataSet->addPoints($rawdata['labels'], "Labels");
|
|
if ($type == 'Line') {
|
|
$DataSet->setSerieWeight("Serie1", $this->default_options[$type]['LineWeight']);
|
|
}
|
|
$DataSet->setSerieDescription("Labels","Report");
|
|
$DataSet->setAbscissa("Labels");
|
|
|
|
// crmv@53923
|
|
if ($rawdata['timestamp']) {
|
|
$DataSet->setXAxisDisplay(AXIS_FORMAT_DATE);
|
|
}
|
|
// crmv@53923e
|
|
|
|
// load palette
|
|
$palfile = $this->column_fields['chart_palette'];
|
|
if (empty($palfile) || !is_readable('modules/Charts/palettes/'.$palfile.'.color')) {
|
|
$palfile = 'default';
|
|
}
|
|
$DataSet->loadPalette("modules/Charts/palettes/$palfile.color", TRUE);
|
|
|
|
$this->initGraphOptions($DataSet);
|
|
|
|
if ($this->default_options['Main']['StretchPalette'])
|
|
$DataSet->stretchPalette('Serie1');
|
|
|
|
|
|
|
|
$myPicture = new pImage($this->image_size_x, $this->image_size_y, $DataSet);
|
|
$myPicture->Antialias = TRUE;
|
|
|
|
// sfondino con righette
|
|
$imgPadding = $this->default_options['Main']['Padding'];
|
|
$imgPaddingLeft = $this->default_options['Main']['PaddingLeft']; // crmv@53923
|
|
$imgPaddingBottom = $this->default_options['Main']['PaddingBottom']; // crmv@53923
|
|
|
|
//$Settings = array("R"=>255, "G"=>255, "B"=>255, "Dash"=>1, "DashR"=>190, "DashG"=>200, "DashB"=>240);
|
|
//$myPicture->drawFilledRectangle($imgPadding,$imgPadding,$this->image_size_x-$imgPadding,$this->image_size_y-$imgPadding,$Settings);
|
|
|
|
// sfondo gradient
|
|
//$Settings = array("StartR"=>230, "StartG"=>240, "StartB"=>255, "EndR"=>200, "EndG"=>210, "EndB"=>240, 'Alpha'=>80);
|
|
//$myPicture->drawGradientArea($imgPadding,$imgPadding,$this->image_size_x-$imgPadding,$this->image_size_y-$imgPadding,DIRECTION_VERTICAL, $Settings);
|
|
|
|
// bordo
|
|
//$myPicture->drawRectangle(0,0,$this->image_size_x-1,$this->image_size_y-1,array("R"=>200,"G"=>200,"B"=>200));
|
|
|
|
// titolo
|
|
//$myPicture->setFontProperties(array("FontName"=>"include/pChart/fonts/VeraBd.ttf","FontSize"=>11));
|
|
//$myPicture->drawGradientArea(0,0,$this->image_size_x,$this->default_options['Main']['TitleHeight'],DIRECTION_VERTICAL,array("StartR"=>255,"StartG"=>255,"StartB"=>255,"EndR"=>200,"EndG"=>200,"EndB"=>200,"Alpha"=>100));
|
|
//$myPicture->drawText(10,$this->default_options['Main']['TitleHeight']/2 - 2,$rawdata['reportname'], array("R"=>0,"G"=>0,"B"=>0, 'Align'=>TEXT_ALIGN_MIDDLE_LEFT));
|
|
|
|
// image map
|
|
$mapname = preg_replace('/\.png/', '_map', $fname);
|
|
$this->map_file = $mapname.'.map';
|
|
$myPicture->initialiseImageMap($mapname, IMAGE_MAP_STORAGE_FILE, basename($mapname), $this->cachedir);
|
|
|
|
// ombra
|
|
if ($this->default_options['Main']['GraphShadow']) {
|
|
$myPicture->setShadow(TRUE,array("X"=>1,"Y"=>1,"R"=>150,"G"=>150,"B"=>150,"Alpha"=>50));
|
|
}
|
|
|
|
// grafico
|
|
$myPicture->setFontProperties(array("FontName"=>'include/pChart/fonts/MYRIADPRO-REGULAR.OTF',"FontSize"=>10,"R"=>100,"G"=>100,"B"=>100));
|
|
$myPicture->setGraphArea($imgPadding+$imgPaddingLeft,$imgPadding+$this->default_options['Main']['TitleHeight'], $this->image_size_x-$imgPadding-1, $this->image_size_y-$imgPadding-$imgPaddingBottom-1); // crmv@53923
|
|
|
|
// spostamento del centro del grafico
|
|
$shift_x = 0;
|
|
$shift_y = 0;
|
|
|
|
// calcolo Y della legenda
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
switch ($this->default_options['Legend']['Position']) {
|
|
case TEXT_ALIGN_BOTTOMLEFT:
|
|
$legend_y = $this->image_size_y - $imgPadding - 20;
|
|
$shift_x = 0;
|
|
$shift_y = -20;
|
|
break;
|
|
case TEXT_ALIGN_TOPLEFT:
|
|
default:
|
|
$legend_y = 20+$this->default_options['Main']['TitleHeight'];
|
|
$shift_x = 40;
|
|
$shift_y = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
switch ($type) {
|
|
case 'BarVertical':
|
|
$myPicture->drawScale($this->default_options['Scale']);
|
|
$myPicture->drawBarChart($this->default_options[$type]);
|
|
break;
|
|
case 'BarHorizontal':
|
|
$myPicture->drawScale($this->default_options['Scale']);
|
|
$myPicture->drawBarChart($this->default_options[$type]);
|
|
break;
|
|
case 'Line':
|
|
$myPicture->drawScale($this->default_options['Scale']);
|
|
$myPicture->drawLineChart($this->default_options[$type]);
|
|
break;
|
|
case 'Pie':
|
|
$PieChart = new pPie($myPicture,$DataSet);
|
|
$PieChart->draw2DPie($this->image_size_x/2+$shift_x, $this->image_size_y/2+$shift_y, $this->default_options[$type]);
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
$myPicture->setShadow(FALSE);
|
|
$PieChart->drawPieLegend(15,$legend_y,$this->default_options['Legend']);
|
|
}
|
|
break;
|
|
case 'Pie3D':
|
|
$PieChart = new pPie($myPicture,$DataSet);
|
|
$PieChart->draw3DPie($this->image_size_x/2+$shift_x, $this->image_size_y/2+$shift_y, $this->default_options[$type]);
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
$myPicture->setShadow(FALSE);
|
|
$PieChart->drawPieLegend(15,$legend_y,$this->default_options['Legend']);
|
|
}
|
|
break;
|
|
case 'Ring':
|
|
$PieChart = new pPie($myPicture,$DataSet);
|
|
$PieChart->draw2DRing($this->image_size_x/2+$shift_x, $this->image_size_y/2+$shift_y, $this->default_options[$type]);
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
$myPicture->setShadow(FALSE);
|
|
$PieChart->drawPieLegend(15,$legend_y,$this->default_options['Legend']);
|
|
}
|
|
break;
|
|
case 'Ring3D':
|
|
$PieChart = new pPie($myPicture,$DataSet);
|
|
$PieChart->draw3DRing($this->image_size_x/2+$shift_x, $this->image_size_y/2+$shift_y, $this->default_options[$type]);
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
$myPicture->setShadow(FALSE);
|
|
$PieChart->drawPieLegend(15,$legend_y,$this->default_options['Legend']);
|
|
}
|
|
break;
|
|
// crmv@53923
|
|
case 'Split':
|
|
$SplitChart = new pSplit($myPicture, $DataSet);
|
|
$SplitChart->drawSplitPath($myPicture,$DataSet,$this->default_options[$type]);
|
|
break;
|
|
case 'Scatter':
|
|
/* Create the Scatter chart object - EXPERIMENTAL */
|
|
|
|
$myPicture->setGraphArea($imgPadding+$imgPaddingLeft,$imgPadding+$this->default_options['Main']['TitleHeight'], $this->image_size_x-$imgPadding-1, $this->image_size_y-$imgPadding-1-20);
|
|
|
|
$scatterChart = new pScatter($myPicture,$DataSet);
|
|
$scatterChart->drawScatterScale();
|
|
$scatterChart->drawScatterLineChart(0,0,$this->default_options[$type]);
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
$myPicture->setShadow(FALSE);
|
|
$scatterChart->drawScatterLegend(20,20,$this->default_options['Legend']);
|
|
}
|
|
|
|
break;
|
|
// crmv@53923e
|
|
}
|
|
|
|
if ($this->default_options['Main']['ShowLegend']) {
|
|
|
|
}
|
|
|
|
// aggiungo warning su dati limitati
|
|
if ($rawdata['limited']) {
|
|
switch ($type) {
|
|
case 'BarVertical':
|
|
$myPicture->drawText($this->image_size_x-10,10, getTranslatedString('LBL_PARTIAL_DATA', 'Charts'), array("R"=>200,"G"=>0,"B"=>0, 'Align'=>TEXT_ALIGN_TOPRIGHT));
|
|
break;
|
|
default:
|
|
$myPicture->drawText($this->image_size_x-10,$this->image_size_y-10, getTranslatedString('LBL_PARTIAL_DATA', 'Charts'), array("R"=>200,"G"=>0,"B"=>0, 'Align'=>TEXT_ALIGN_BOTTOMRIGHT));
|
|
break;
|
|
}
|
|
}
|
|
|
|
// render image
|
|
$myPicture->Render($fname);
|
|
$this->cachefile_date[$this->cachefield] = filemtime($fname);
|
|
|
|
// anteprima
|
|
//$this->createThumbnail($fname);
|
|
|
|
// save it into database
|
|
$chartid = intval($this->column_fields["record_id"]);
|
|
if ($chartid > 0) {
|
|
$adb->pquery("update {$table_prefix}_chartscache set {$this->cachefield} = ? where {$this->table_index} = ?", array($fname, $chartid));
|
|
}
|
|
|
|
return $fname;
|
|
}
|
|
|
|
function getMapData() {
|
|
$mapfile = $this->map_file;
|
|
|
|
if (empty($mapfile) || !is_readable($mapfile)) return array();
|
|
|
|
$ret = '';
|
|
$Handle = @fopen($mapfile, "r");
|
|
if ($Handle) {
|
|
while (($Buffer = fgets($Handle, 4096)) !== false) {
|
|
$ret .= $Buffer;
|
|
}
|
|
@fclose($Handle);
|
|
}
|
|
|
|
// now parse it
|
|
$retzones = array();
|
|
$zones = explode("\r\n", $ret);
|
|
foreach ($zones as $zdata) {
|
|
$zinfo = explode(IMAGE_MAP_DELIMITER, $zdata);
|
|
if (empty($zinfo[0]) || empty($zinfo[1])) continue;
|
|
$retzones[] = array(
|
|
'shape'=>$zinfo[0],
|
|
'coords'=>$zinfo[1],
|
|
'color'=>$zinfo[2],
|
|
'label'=>$zinfo[3],
|
|
'value'=>formatUserNumber(floatval($zinfo[4])), // crmv@92350
|
|
'percent'=>$zinfo[5],
|
|
);
|
|
|
|
}
|
|
|
|
return $retzones;
|
|
}
|
|
|
|
// crmv@172355
|
|
public function getReportRunObj() {
|
|
global $adb, $table_prefix;
|
|
|
|
$reportid = $this->column_fields['reportid'];
|
|
if ($reportid > 0) {
|
|
$folderid = getSingleFieldValue($table_prefix.'_report', 'folderid', 'reportid', $reportid);
|
|
$sdkrep = SDK::getReport($reportid, $folderid);
|
|
if (!is_null($sdkrep)) {
|
|
require_once($sdkrep['reportrun']);
|
|
$oReportRun = new $sdkrep['runclass']($reportid);
|
|
} else {
|
|
$oReportRun = ReportRun::getInstance($reportid);
|
|
}
|
|
}
|
|
return $oReportRun;
|
|
}
|
|
|
|
// ricalcola il report
|
|
// crmv@97862
|
|
function reloadReport() {
|
|
$oReportRun = $this->getReportRunObj();
|
|
if ($oReportRun) {
|
|
if ($oReportRun instanceof ReportRun && !$oReportRun->hasSummary()) return; // crmv@172355 - allow sdk reports
|
|
$oReportRun->setReportTab('COUNT');
|
|
$oReportRun->setOutputFormat('NULL');
|
|
$oReportRun->GenerateReport();
|
|
$this->invalidateCache();
|
|
}
|
|
}
|
|
// crmv@97862e crmv@172355e
|
|
|
|
// crmv@133997
|
|
/**
|
|
* Return the color for each cluster
|
|
*/
|
|
public function getReportColors() {
|
|
$colors = array();
|
|
$reportid = $this->column_fields['reportid'];
|
|
if ($reportid > 0) {
|
|
$REP = Reports::getInstance();
|
|
$clusters = $REP->getClusters($reportid);
|
|
if (is_array($clusters) && count($clusters) > 0) {
|
|
foreach ($clusters as $cluster) {
|
|
if ($cluster['name'] && $cluster['color']) {
|
|
$colors[$cluster['name']] = $cluster['color'];
|
|
}
|
|
}
|
|
if (count($colors) > 0) {
|
|
// add the empty color (grey)
|
|
$colors['-'] = '#a0a0a0';
|
|
}
|
|
}
|
|
}
|
|
return $colors;
|
|
}
|
|
// crmv@133997e
|
|
|
|
// invalida la cache immagine
|
|
// TODO: invalida tutte le cache
|
|
function invalidateCache() {
|
|
global $adb, $table_prefix;
|
|
$chartid = $this->column_fields["record_id"];
|
|
|
|
$adb->pquery("update {$table_prefix}_chartscache set {$this->cachefield} = NULL where {$this->table_index} = ?", array($chartid));
|
|
// delete files
|
|
// TODO: thumbnails
|
|
if (is_writable($this->column_fields[$this->cachefield])) {
|
|
$mapname = preg_replace('/\.png/', '_map.map', $this->column_fields[$this->cachefield]);
|
|
$thumbname = preg_replace('/\.png/', '_thumb.png', $this->column_fields[$this->cachefield]);
|
|
@unlink($this->column_fields[$this->cachefield]);
|
|
@unlink($mapname);
|
|
@unlink($thumbname);
|
|
$this->column_fields[$this->cachefield] = '';
|
|
unset($this->cachefile_date[$this->cachefield]);
|
|
$this->map_file = null;
|
|
}
|
|
}
|
|
|
|
// crea una anteprima del grafico
|
|
function createThumbnail($filename) {
|
|
|
|
if ($this->chartLibrary == 'ChartJS') {
|
|
// just set the sizes
|
|
$newy = intval(floatval($this->thumbnail_size) * $this->image_size_y / $this->image_size_x);
|
|
$this->image_size_x = $this->thumbnail_size;
|
|
$this->image_size_y = $newy;
|
|
return null;
|
|
}
|
|
|
|
if (function_exists('imagecopyresampled') && is_readable($filename)) {
|
|
$image_src = imagecreatefrompng($filename);
|
|
$newy = intval(floatval($this->thumbnail_size) * $this->image_size_y / $this->image_size_x);
|
|
$image_dest = imagecreatetruecolor($this->thumbnail_size, $newy);
|
|
|
|
imagecopyresampled($image_dest, $image_src, 0, 0, 0, 0, $this->thumbnail_size, $newy, $this->image_size_x, $this->image_size_y);
|
|
|
|
$outname = preg_replace('/\.png/', '_thumb.png', $filename);
|
|
imagepng($image_dest, $outname);
|
|
return $outname;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function renderChart($showdate = true, $showborder = true, $viewreportlink = false) { // crmv@128369
|
|
global $app_strings, $mod_strings, $theme, $current_language;
|
|
|
|
// map data is used only for php generated charts
|
|
if ($this->chartLibrary == 'pChart') {
|
|
$fname = $this->generateChart();
|
|
$mapdata = $this->getMapData();
|
|
$chartdata = null;
|
|
} elseif ($this->chartLibrary == 'ChartJS') {
|
|
$fname = null;
|
|
$mapdata = null;
|
|
$chartdata = $this->generateChart();
|
|
}
|
|
|
|
$smarty = new VteSmarty();
|
|
$smarty->assign('APP', $app_strings);
|
|
$smarty->assign('MOD', return_module_language($current_language,'Charts'));
|
|
$smarty->assign('THEME', $theme);
|
|
$smarty->assign('IMAGE_PATH', "themes/$theme/images/");
|
|
|
|
$smarty->assign('CHART_ID', $this->column_fields['record_id']);
|
|
$smarty->assign('REPORTID', $this->column_fields['reportid']); // crmv@128369
|
|
$smarty->assign('CHART_TITLE', $this->getChartTitle());
|
|
$smarty->assign('CHART_PATH', $fname);
|
|
// variables used for home block
|
|
$smarty->assign('HOME_STUFFID', $this->homestuffid);
|
|
$smarty->assign('HOME_STUFFSIZE', $this->homestuffsize);
|
|
|
|
$smarty->assign('CHART_SHOWREPORTLINK', $viewreportlink); // crmv@128369
|
|
$smarty->assign('CHART_SHOWBORDER', $showborder);
|
|
$smarty->assign('CHART_SHOWDATE', $showdate);
|
|
$smarty->assign('CHART_LIMIT_DATA_N', $this->limit_data); // crmv@191909
|
|
if ($showdate) {
|
|
// crmv@134727
|
|
if ($this->chartLibrary == 'pChart') {
|
|
$smarty->assign('CHART_LASTUPDATE', $this->cachefile_date[$this->cachefield]);
|
|
$extdate = date('Y-m-d H:i:s', $this->cachefile_date[$this->cachefield]);
|
|
} elseif ($this->chartLibrary == 'ChartJS' && $chartdata['generatedtime']) {
|
|
$smarty->assign('CHART_LASTUPDATE', strtotime($chartdata['generatedtime']));
|
|
$extdate = $chartdata['generatedtime'];
|
|
}
|
|
if ($extdate) {
|
|
$smarty->assign('CHART_LASTUPDATE_DISPLAY', getDisplayDate($extdate));
|
|
$smarty->assign('CHART_LASTUPDATE_RELATIVE', getFriendlyDate($extdate));
|
|
}
|
|
// crmv@134727e
|
|
}
|
|
|
|
$smarty->assign('CHART_MAP', $mapdata);
|
|
$smarty->assign('CHART_DATA', $chartdata);
|
|
|
|
if ($this->chartLibrary == 'pChart') {
|
|
$htmldata = $smarty->fetch('modules/Charts/RenderChart.tpl');
|
|
} elseif ($this->chartLibrary == 'ChartJS') {
|
|
$htmldata = $smarty->fetch('modules/Charts/RenderChartJS.tpl');
|
|
} else {
|
|
throw new Exception("Chart library '{$this->chartLibrary}' is not supported");
|
|
}
|
|
return $htmldata;
|
|
}
|
|
|
|
function renderHomeBlock() {
|
|
global $adb, $table_prefix, $current_user;
|
|
|
|
$size = $this->homestuffsize;
|
|
if (empty($size)) $size = 1;
|
|
|
|
// get home layout
|
|
$layout = 4;
|
|
$res = $adb->pquery("select layout from {$table_prefix}_home_layout where userid = ?", array($current_user->id));
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
$layout = intval($adb->query_result($res, 0, 'layout'));
|
|
if ($layout == 0) $layout = 4;
|
|
}
|
|
|
|
switch ($layout) {
|
|
case 2:
|
|
$single_size = 520;
|
|
break;
|
|
case 3:
|
|
$single_size = 360;
|
|
break;
|
|
case 4:
|
|
default:
|
|
$single_size = 260;
|
|
}
|
|
|
|
$this->setCacheField('chart_file_home');
|
|
$this->image_size_x = $single_size * $size;
|
|
$this->image_size_y = 260;
|
|
return $this->renderChart(true, false, true); // crmv@128369
|
|
}
|
|
|
|
// crmv83340
|
|
function renderModuleHomeBlock($layout = 4) {
|
|
global $adb, $table_prefix, $current_user;
|
|
|
|
$size = $this->homestuffsize;
|
|
if (empty($size)) $size = 1;
|
|
|
|
switch ($layout) {
|
|
case 2:
|
|
$single_size = 520;
|
|
break;
|
|
case 3:
|
|
$single_size = 360;
|
|
break;
|
|
case 4:
|
|
default:
|
|
$single_size = 260;
|
|
}
|
|
|
|
//$this->setCacheField('chart_file_home');
|
|
$this->image_size_x = $single_size * $size;
|
|
$this->image_size_y = 260;
|
|
return $this->renderChart(true, false, true); // crmv@128369
|
|
|
|
}
|
|
// crmv83340e
|
|
|
|
// restituisce un array di istanze per i grafici
|
|
function getChartsForReport($reportid, $usefilters = false) { // crmv@31209
|
|
global $adb, $table_prefix;
|
|
|
|
$ret = array();
|
|
$res = $adb->pquery("select {$this->table_index} as chartid from {$this->table_name} inner join {$table_prefix}_crmentity crment on crment.crmid = {$this->table_name}.{$this->table_index} where crment.deleted = 0 and reportid = ?", array($reportid));
|
|
if ($res) {
|
|
while ($row = $adb->fetchByAssoc($res, -1, false)) {
|
|
$chid = $row['chartid'];
|
|
$chclass = CRMEntity::getInstance('Charts');
|
|
$chclass->retrieve_entity_info($chid, 'Charts');
|
|
if ($usefilters) $chclass->filtered_data = true; // crmv@31209
|
|
$ret[] = $chclass;
|
|
}
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// crmv@172355
|
|
/**
|
|
* Count how many charts exists for the specified report
|
|
*/
|
|
public function countChartsForReport($reportid) {
|
|
global $adb, $table_prefix;
|
|
|
|
$res = $adb->pquerySlave('Reports', // crmv@185894
|
|
"SELECT COUNT(*) AS cnt
|
|
FROM {$this->table_name} ch
|
|
INNER JOIN {$table_prefix}_crmentity c ON c.crmid = ch.{$this->table_index} AND c.deleted = 0
|
|
WHERE ch.reportid = ?", array($reportid)
|
|
);
|
|
if ($res && $adb->num_rows($res) > 0) {
|
|
return $adb->query_result_no_html($res, 0, 'cnt');
|
|
}
|
|
return 0;
|
|
}
|
|
// crmv@172355e
|
|
|
|
function getChartTypes() {
|
|
global $adb, $current_user, $table_prefix;
|
|
|
|
$chtypes = getAssignedPicklistValues('chart_type', $current_user->roleid, $adb, 'Charts');
|
|
|
|
return $chtypes;
|
|
}
|
|
|
|
function getQuickCreateDefault($module, $qcreate_array, $search_field, $search_text) {
|
|
$col_fields = parent::getQuickCreateDefault($module, $qcreate_array, $search_field, $search_text);
|
|
|
|
// add defaults
|
|
$col_fields['chart_labels'] = 1;
|
|
$col_fields['chart_merge_small'] = 1;
|
|
|
|
return $col_fields;
|
|
}
|
|
|
|
// crmv@30967
|
|
function getFolderContent($folderid) {
|
|
global $adb, $table_prefix, $current_user, $app_strings, $mod_strings;
|
|
|
|
$folderinfo = getEntityFolder($folderid);
|
|
|
|
$queryGenerator = QueryGenerator::getInstance('Charts', $current_user);
|
|
$queryGenerator->initForDefaultCustomView();
|
|
$queryGenerator->addField('chart_filename');
|
|
$list_query = $queryGenerator->getQuery();
|
|
// only in selected folder
|
|
$list_query .= " AND {$this->table_name}.folderid = '$folderid'";
|
|
// order by most recent first
|
|
$list_query .= " ORDER BY {$table_prefix}_crmentity.modifiedtime DESC";
|
|
|
|
$count = 0;
|
|
$res = $adb->query(replaceSelectQuery($list_query,'count(*) as cnt'));
|
|
if ($res) $count = $adb->query_result($res,0,'cnt');
|
|
|
|
$smarty = new VteSmarty();
|
|
$smarty->assign('FOLDERINFO', $folderinfo);
|
|
$smarty->assign('APP', $app_strings);
|
|
$smarty->assign('MOD', $mod_strings);
|
|
$smarty->assign('TOTALCOUNT', $count);
|
|
|
|
// retrieve the first documents as a preview
|
|
$html = '';
|
|
$res = $adb->limitQuery($list_query, 0, 3);
|
|
if ($res) {
|
|
$arr = array();
|
|
while ($row = $adb->fetchByAssoc($res)) {
|
|
$arr[] = $row;
|
|
}
|
|
$smarty->assign('FOLDERDATA', $arr);
|
|
}
|
|
$html = $smarty->fetch('modules/Charts/FolderTooltip.tpl');
|
|
|
|
return array('count'=>$count, 'html'=>$html);
|
|
}
|
|
// crmv@30967e
|
|
|
|
/**
|
|
* Invoked when special actions are performed on the module.
|
|
* @param String Module name
|
|
* @param String Event Type (module.postinstall, module.disabled, module.enabled, module.preuninstall)
|
|
*/
|
|
function vtlib_handler($modulename, $event_type) {
|
|
global $adb, $table_prefix;
|
|
|
|
if($event_type == 'module.postinstall') {
|
|
|
|
$clModule = Vtecrm_Module::getInstance($modulename);
|
|
$clModule->disableTools(Array('Import', 'Export', 'DuplicatesHandling'));
|
|
|
|
$adb->pquery('UPDATE '.$table_prefix.'_tab SET customized=0 WHERE name=?', array($modulename));
|
|
|
|
// blocco info chiuso di default
|
|
//$adb->pquery("update {$table_prefix}_blocks set display_status = 0 where blocklabel = ?", array('LBL_CHARTS_INFORMATION'));
|
|
|
|
$clModule->hide(array('hide_report'=>1)); // crmv@38798
|
|
|
|
$modInstance = CRMEntity::getInstance($modulename);
|
|
// hide it from many places
|
|
if (method_exists($modInstance, 'hide'))
|
|
$modInstance->hide(array('hide_module_manager'=>1,'hide_profile'=>1,'hide_report'=>1));
|
|
|
|
if(!Vtecrm_Utils::CheckTable($this->table_name)) {
|
|
Vtecrm_Utils::CreateTable(
|
|
$this->table_name,
|
|
"{$this->table_index} I(19) PRIMARY",
|
|
true);
|
|
}
|
|
if(!Vtecrm_Utils::CheckTable($this->customFieldTable[0])) {
|
|
Vtecrm_Utils::CreateTable(
|
|
$this->customFieldTable[0],
|
|
"{$this->customFieldTable[1]} I(19) PRIMARY",
|
|
true);
|
|
}
|
|
|
|
$ctable = $table_prefix.'_chartscache';
|
|
if(!Vtecrm_Utils::CheckTable($ctable)) {
|
|
Vtecrm_Utils::CreateTable(
|
|
$ctable,
|
|
"{$this->customFieldTable[1]} I(19) PRIMARY",
|
|
true);
|
|
}
|
|
|
|
// table for charts in homepage
|
|
$hometable = $table_prefix.'_homecharts';
|
|
if(!Vtecrm_Utils::CheckTable($hometable)) {
|
|
Vtecrm_Utils::CreateTable(
|
|
$hometable,
|
|
"stuffid I(19) PRIMARY,
|
|
chartid I(19)",
|
|
true);
|
|
}
|
|
|
|
if (class_exists('SDK')) {
|
|
SDK::file2DbLanguages($modulename);
|
|
SDK::setAdvancedPermissionFunction('Charts', 'chartsPermission', 'modules/Charts/SDK/advPermission.php');
|
|
|
|
// extra languages
|
|
SDK::setLanguageEntry('APP_STRINGS', 'it_it', 'SINGLE_Charts', 'Grafico');
|
|
SDK::setLanguageEntry('APP_STRINGS', 'en_us', 'SINGLE_Charts', 'Chart');
|
|
SDK::setLanguageEntry('Home', 'it_it', 'LBL_HOME_CHART_NAME', 'Nome Grafico');
|
|
SDK::setLanguageEntry('Home', 'en_us', 'LBL_HOME_CHART_NAME', 'Chart Name');
|
|
}
|
|
|
|
// add a default folder
|
|
addEntityFolder('Charts', 'Default', '', 1);
|
|
// create examples
|
|
include('modules/Charts/InstallExamples.php');
|
|
|
|
} else if($event_type == 'module.disabled') {
|
|
// TODO Handle actions when this module is disabled.
|
|
} else if($event_type == 'module.enabled') {
|
|
// TODO Handle actions when this module is enabled.
|
|
} else if($event_type == 'module.preuninstall') {
|
|
// TODO Handle actions when this module is about to be deleted.
|
|
} else if($event_type == 'module.preupdate') {
|
|
// TODO Handle actions before this module is updated.
|
|
} else if($event_type == 'module.postupdate') {
|
|
// reload translations from module files
|
|
// TODO: non sovrascrivere personalizzazioni
|
|
if (class_exists('SDK')) {
|
|
SDK::deleteLanguage($modulename);
|
|
SDK::file2DbLanguages($modulename);
|
|
SDK::setLanguageEntry('APP_STRINGS', 'it_it', 'SINGLE_Charts', 'Grafico');
|
|
SDK::setLanguageEntry('APP_STRINGS', 'en_us', 'SINGLE_Charts', 'Chart');
|
|
}
|
|
}
|
|
}
|
|
|
|
function trash($module, $id) {
|
|
global $adb, $table_prefix;
|
|
parent::trash($module, $id);
|
|
|
|
// delete charts from home page
|
|
$stuffids = array();
|
|
$res = $adb->pquery("select stuffid from {$table_prefix}_homecharts where chartid = ?", array($id));
|
|
if ($res) {
|
|
while ($row = $adb->fetchByAssoc($res, -1, false)) $stuffids[] = $row['stuffid'];
|
|
|
|
if (count($stuffids) > 0) {
|
|
$adb->pquery("delete from {$table_prefix}_homecharts where stuffid in (".generateQuestionMarks($stuffids).")", $stuffids);
|
|
$adb->pquery("delete from {$table_prefix}_homestuff where stuffid in (".generateQuestionMarks($stuffids).")", $stuffids);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Handle saving related module information.
|
|
* NOTE: This function has been added to CRMEntity (base class).
|
|
* You can override the behavior by re-defining it here.
|
|
*/
|
|
/*
|
|
function save_related_module($module, $crmid, $with_module, $with_crmid) {
|
|
parent::save_related_module($module, $crmid, $with_module, $with_crmid);
|
|
//...
|
|
}
|
|
*/
|
|
|
|
/**
|
|
* Handle deleting related module information.
|
|
* NOTE: This function has been added to CRMEntity (base class).
|
|
* You can override the behavior by re-defining it here.
|
|
*/
|
|
//function delete_related_module($module, $crmid, $with_module, $with_crmid) { }
|
|
|
|
/**
|
|
* Handle getting related list information.
|
|
* NOTE: This function has been added to CRMEntity (base class).
|
|
* You can override the behavior by re-defining it here.
|
|
*/
|
|
//function get_related_list($id, $cur_tab_id, $rel_tab_id, $actions=false) { }
|
|
|
|
/**
|
|
* Handle getting dependents list information.
|
|
* NOTE: This function has been added to CRMEntity (base class).
|
|
* You can override the behavior by re-defining it here.
|
|
*/
|
|
//function get_dependents_list($id, $cur_tab_id, $rel_tab_id, $actions=false) { }
|
|
|
|
// widget code
|
|
static function getWidget($name) {
|
|
if ($name == 'DetailViewBlockChartWidget' && isPermitted('Charts', 'DetailView') == 'yes') {
|
|
require_once dirname(__FILE__) . '/widgets/DetailViewBlockChart.php';
|
|
return (new Charts_DetailViewBlockChartWidget(null));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// output a rgb style palette
|
|
function parsePaletteFile($file) {
|
|
$rgbPalette = array();
|
|
$data = @file_get_contents($file);
|
|
if (empty($data)) return $rgbPalette;
|
|
|
|
$lines = array_filter(explode("\n", str_replace("\r", '', $data)));
|
|
foreach ($lines as $line) {
|
|
list($r, $g, $b, $a) = array_map('trim', explode(",", strtolower($line)));
|
|
$r = intval($r,0);
|
|
$g = intval($g,0);
|
|
$b = intval($b,0);
|
|
$a2 = intval($a);
|
|
if ($a === null || $a === '' || $a2 == 100) {
|
|
$rgbPalette[] = array($r, $g, $b);
|
|
} else {
|
|
$rgbPalette[] = array($r, $g, $b, $a2);
|
|
}
|
|
}
|
|
|
|
return $rgbPalette;
|
|
}
|
|
|
|
// convert a rgb palette into a css-style palette
|
|
function paletteRGB2Css($rgbPalette) {
|
|
$cpalette = array();
|
|
foreach ($rgbPalette as $c) {
|
|
if (!isset($c[3]) || $c[3] === '' || $c[3] == 100) {
|
|
$out = sprintf("#%02x%02x%02x", $c[0], $c[1], $c[2]);
|
|
} else {
|
|
$out = sprintf("rgba(%d,%d,%d,%d)", $c[0], $c[1], $c[2], $c[3]);
|
|
}
|
|
$cpalette[] = $out;
|
|
}
|
|
return $cpalette;
|
|
}
|
|
|
|
// crmv@133997
|
|
// convert a css palette into a rgb palette
|
|
function paletteCss2RGB($cssPalette) {
|
|
$cpalette = array();
|
|
foreach ($cssPalette as $c) {
|
|
if ($c[0] == '#') {
|
|
if (strlen($c) == 4) {
|
|
// short format
|
|
$out = array(hexdec($c[1]), hexdec($c[2]), hexdec($c[3]));
|
|
} else {
|
|
$out = array(hexdec(substr($c, 1, 2)), hexdec(substr($c, 3, 2)), hexdec(substr($c, 5, 2)));
|
|
}
|
|
} else {
|
|
// other formarts not supported
|
|
}
|
|
$cpalette[] = $out;
|
|
}
|
|
return $cpalette;
|
|
}
|
|
// crmv@133997e
|
|
|
|
function variatePalette($rgbPalette, $variationType, $variationParams = array()) {
|
|
$vpalette = array();
|
|
|
|
if ($variationType == 'lighten' || $variationType == 'darken') {
|
|
$perc = $variationParams['percentage'] ?: 10;
|
|
foreach ($rgbPalette as $color) {
|
|
$hsl = self::rgb2hsl($color[0], $color[1], $color[2]);
|
|
if ($variationType == 'lighten') {
|
|
$hsl[2] = max(0.0, min($hsl[2] * (1.0 + ($perc / 100)), 1.0));
|
|
} else {
|
|
$hsl[2] = max(0.0, min($hsl[2] * (1.0 - ($perc / 100)), 1.0));
|
|
}
|
|
$rgb = self::hsl2rgb($hsl[0], $hsl[1], $hsl[2]);
|
|
$vpalette[] = $rgb;
|
|
}
|
|
} else {
|
|
// other variations not supported
|
|
$vpalette = $rgbPalette;
|
|
}
|
|
|
|
return $vpalette;
|
|
}
|
|
|
|
// some helper functions to manage the palette
|
|
static function rgb2hsl($r, $g, $b) {
|
|
$var_R = ($r / 255);
|
|
$var_G = ($g / 255);
|
|
$var_B = ($b / 255);
|
|
|
|
$var_Min = min($var_R, $var_G, $var_B);
|
|
$var_Max = max($var_R, $var_G, $var_B);
|
|
$del_Max = $var_Max - $var_Min;
|
|
|
|
$v = $var_Max;
|
|
|
|
if ($del_Max == 0) {
|
|
$h = 0;
|
|
$s = 0;
|
|
} else {
|
|
$s = $del_Max / $var_Max;
|
|
|
|
$del_R = ( ( ( $var_Max - $var_R ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
|
|
$del_G = ( ( ( $var_Max - $var_G ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
|
|
$del_B = ( ( ( $var_Max - $var_B ) / 6 ) + ( $del_Max / 2 ) ) / $del_Max;
|
|
|
|
if ($var_R == $var_Max) $h = $del_B - $del_G;
|
|
else if ($var_G == $var_Max) $h = ( 1 / 3 ) + $del_R - $del_B;
|
|
else if ($var_B == $var_Max) $h = ( 2 / 3 ) + $del_G - $del_R;
|
|
|
|
if ($h < 0) $h++;
|
|
if ($h > 1) $h--;
|
|
}
|
|
|
|
return array($h, $s, $v);
|
|
}
|
|
|
|
static function hsl2rgb($h, $s, $v) {
|
|
if($s == 0) {
|
|
$r = $g = $b = $v * 255;
|
|
} else {
|
|
$var_H = $h * 6;
|
|
$var_i = floor( $var_H );
|
|
$var_1 = $v * ( 1 - $s );
|
|
$var_2 = $v * ( 1 - $s * ( $var_H - $var_i ) );
|
|
$var_3 = $v * ( 1 - $s * (1 - ( $var_H - $var_i ) ) );
|
|
|
|
if ($var_i == 0) { $var_R = $v ; $var_G = $var_3 ; $var_B = $var_1 ; }
|
|
else if ($var_i == 1) { $var_R = $var_2 ; $var_G = $v ; $var_B = $var_1 ; }
|
|
else if ($var_i == 2) { $var_R = $var_1 ; $var_G = $v ; $var_B = $var_3 ; }
|
|
else if ($var_i == 3) { $var_R = $var_1 ; $var_G = $var_2 ; $var_B = $v ; }
|
|
else if ($var_i == 4) { $var_R = $var_3 ; $var_G = $var_1 ; $var_B = $v ; }
|
|
else { $var_R = $v ; $var_G = $var_1 ; $var_B = $var_2 ; }
|
|
|
|
$r = $var_R * 255;
|
|
$g = $var_G * 255;
|
|
$b = $var_B * 255;
|
|
}
|
|
return array($r, $g, $b);
|
|
}
|
|
|
|
}
|
|
?>
|