* @version $Id$ * @access public * @license http://opensource.org/licenses/gpl-3.0.html */ if(!function_exists('get_associated_projects')) { function get_associated_projects($id) { $str = ''; $projects = $GLOBALS['sql_object'] ->DBSelect(SQL_get_associated_projects($id)); if(isset($projects[0]['project_name'])) { $str = ''; $content = ''; foreach($projects as $project) { $content .= '
  • '.formatText($project['project_name'], '2HTML').'
  • '; } $str = sprintf($str, $content); } return empty_none($str); } } if(!function_exists('getMenuFilter')) { /** * getMenuFilter() * * @param array $tags * @return string */ function getMenuFilter ($tags = array()) { footerAddJS('../lib/js/jquery-tag-filtering/jquery.tagfiltering.simo.js'); addDynamicCSS('../lib/js/jquery-tag-filtering/jquery.tagfiltering.simo.css'); // one call to apply many filters from several lists (ul) with same css class and using distincts data-* attributes // to comment if individual filtering are applied footerAddInlineJS('$("ul.filter-menu").tagfiltering({target_attr:"data-tags,data-types", separator:";"});'); // export Javascript part $js = '$("#save-export").click( function() { var to_export = []; var $items = $(".filter-items").children(); // we populate the array to send with ajax $items.each(function() { if($(this).is(":visible")) { var curval = $(this).attr("data-id"); // we check if not in array yet if($.inArray( curval,to_export) == -1) to_export.push($(this).attr("data-id")); } }); alertify.success("'. _t('items', 'selected').'".replace("%s", to_export.length)); $.ajax({ type: "POST", data: {to_export:to_export}, url: "../dashboard/_ajax_save.php?token='.SECRET_KEY.'", success: function(msg){ window.location = "../admin/index.php?rub=dashboard&todo=report"; } }); });'; footerAddInlineJS($js); $filter_menu = '
    '._t('filter', 'content').'
    '; $filter_menu .= ''; return $filter_menu; } } if(!function_exists('getTypesMenuFilter')) { /** * getTagsMenuFilter() * * get tags menu filter * @param array $tags * @return string */ function getTypesMenuFilter ($types) { $filter = ''; // we display filter if at least 1 values exists if(count($types) >= 1) { $options = ''; $a = array(); foreach($types as $key => $val) { if(!in_array($key, $a)) { $options .= '
  • '.formatText(mb_ucfirst($val), '2HTML').'
  • '; array_push($a, $key); } } $filter .= sprintf('

    %s

    ', _t('filter', 'by_type'), $options); } return $filter; } } if(!function_exists('getTagsMenuFilter')) { /** * getTagsMenuFilter() * * get tags menu filter * @param array $tags * @return string */ function getTagsMenuFilter ($tags) { $filter = ''; // we display filter if at least 1 values exists if(count($tags) >= 1) { $options = ''; $a = array(); foreach($tags as $item) { if(!in_array($item['tag_id'], $a)) { $options .= '
  • '.$item['tag_name'].'
  • '; array_push($a, $item['tag_id']); } } $filter .= sprintf('

    %s

    ', _t('filter', 'by_tag'), $options); } return $filter; } } if(!function_exists('getPositionfromValue')) { function getPositionfromValue ($value, $indicator, $threshold_value){ if ($indicator['sdii_max_value']==0) { $max_value=0.000001; } else { $max_value=$indicator['sdii_max_value']; } if ($indicator['sdii_min_value']==0) { $min_value=0.000001; } else { $min_value=$indicator['sdii_min_value']; } if ($indicator['sdii_threshold_relative']=='Y') { $unitup = 50 / ($max_value - $threshold_value); $unitdown = 50 / ( $threshold_value - $min_value); if ($value > $threshold_value) $result = 50 + (($value - $threshold_value) *$unitup); else $result = 50 -( ($threshold_value - $value ) *$unitdown ); } else{ if(($max_value - $threshold_value) <> 0) $unitdown = 50 / ($max_value - $threshold_value); if(($threshold_value - $min_value) <> 0) $unitup = 50 / ($threshold_value - $min_value); if ($value > $threshold_value) $result=50 -( ($value - $threshold_value) * $unitdown); else $result = 50 + (( $threshold_value - $value ) * $unitup); } return (int)$result; } } if(!function_exists('getIndicatorInfoBox')) { function getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class= '') { if($indicator['sdii_nature'] == 'quantitative') { $display_min = empty_nc($indicator['sdii_min_value']); $display_max = empty_nc($indicator['sdii_max_value']); $display_threshold = empty_nc(fnumber_format($threshold_value, 'auto', false)); } else { $a = getBooleanValues($indicator); if($a) { $index = array(); foreach ($a as $key => $value) { array_push($index, $key); } } $display_min = $a[min($index)]; $display_max = $a[max($index)]; if(!empty($threshold_value)) $display_threshold = $a[$threshold_value]; else $display_threshold = empty_nc(''); if(count($index) < 2) { logfile(LOG_MAINFILE, array('[WARNING] no min/max defined for boolean / qualitative indicator. Check if {} boolean values are defined in comment field.', 'indicator_id=' . $indicator['sdii_id'])); } } $content = "

    ".ucfirst(_t('dashboard','value'))." : ".fnumber_format($current_value, 'auto', false)." (".formatText($indicator['sdii_unit']).")

    ". "

    ".ucfirst(_t('sdi','min_value'))." : ".$display_min."

    ". "

    ".ucfirst(_t('sdi','max_value'))." : ".$display_max."

    ". "

    ".ucfirst(_t('sdi','threshold_value'))." : ".$display_threshold."

    ". "
    "; return $content; } } if(!function_exists('getGaugeViz')) { function getGaugeViz($sql_object, $scale_id, $indicator, $threshold_value, $cursorcssposition) { //$cursorcssposition is used to adjust cursor position depending on the container/context $req_sdiav=SQL_getAllValue("SCA", $scale_id, $indicator['sdii_id']); $result_value = $sql_object -> DBSelect($req_sdiav); // values are stored if ($result_value <> false){ // we handle multivalues if(!empty($result_value[0]['sdiv_multivalue'])) { $data = unserialize($result_value[0]['sdiv_multivalue']); $current_value = $data[0]['_total']; // we handle simple values } else { $current_value = $result_value[0]['sdiv_value']; } $value_cursor1 = getPositionfromValue ($current_value, $indicator, $threshold_value); // Pour la jauge avec image // @todo remove when removing gauge image // $value_cursor = 111 - $value_cursor1 + $cursorcssposition; // $value_cursor = -111 + $value_cursor1 + $cursorcssposition; // 3 is half width of the cursor image. Positionning $value_cursor to -111 will display the cursor at the begining of the gauge // Pour la jauge avec image $value_cursor = $value_cursor1 * 150 / 100 - 2; // on rapporte le placement à la largeur du bloc et on soustrait la moitié de la largeur du curseur, soit 4/2, ou 2 pixels } else { $value_cursor = 0; } // there is no value if ($result_value == false) { $gauge= 'gauge_grey.gif'; $gaugeclass = 'g-no-value'; $current_value = _t('dashboard','novalue'); $cursor_visibility = 'hidden'; $class="indicator-no-data"; } // min, max and threshold are not set together. No display allowed elseif(is_null($indicator['sdii_max_value']) || is_null($indicator['sdii_min_value']) || is_null($threshold_value)) { $gauge= 'gauge_red.gif'; $gaugeclass = 'g-no-fit'; $current_value = $result_value[0]['sdiv_value']; $cursor_visibility = 'hidden'; $class="indicator-no-cursor"; } // there is at least one value and min, max and threshold are set together else { $gauge= 'gauge.gif'; $gaugeclass = 'gradient'; $cursor_visibility = 'visible'; $class=""; // we handle multivalues if(!empty($result_value[0]['sdiv_multivalue'])) { $data = unserialize($result_value[0]['sdiv_multivalue']); $current_value = $data[0]['_total']; // we handle simple values } else { $current_value = $result_value[0]['sdiv_value']; } } if(CURRENT_APP == 'admin') { $link = "index.php?rub=dashboard&todo=det&id=".$indicator['sdii_id']."&scale_id=".$scale_id; } else { $link = HrefMaker(array('rub'=> $GLOBALS['links'][U_L]['dashboard']['linkvalue'],'id'=>$indicator['sdii_id'], 'parentid'=> $scale_id)); } $link="javascript:void(0);"; // @todo remove when removing gauge image // $listing = "
    // // \"".ucfirst(_t('dashboard','value')).""; // $listing .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); // $listing .= "\"\""; $listing = "
    "; $listing .= "
    "; $listing .= "
    "; // $listing .= "\"\""; $listing .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); $listing .= "
    "; if(isset($result_value[0])) { $arr = array_reverse($result_value); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $listing .= '
    ' . $lastyear . '
    '; } $listing .= getTendency($result_value, $indicator); // $listing .= "\t (".strtolower(fnumber_format($current_value, 'auto', false)).")\n"; return $listing; } } if(!function_exists('getRawViz')) { function getRawViz($sql_object, $scale_id, $indicator, $threshold_value) { $req_sdiav=SQL_getAllValue("SCA", $scale_id, $indicator['sdii_id']); $result_value = $sql_object -> DBSelect($req_sdiav); $str = '
    '; // there is no value if ($result_value==false) { $str .= '-'; $current_value = _t('dashboard','novalue'); $class="indicator-no-data"; // some values are there } else { // we handle multivalues if(!empty($result_value[0]['sdiv_multivalue'])) { $data = unserialize($result_value[0]['sdiv_multivalue']); $str .= ''.fnumber_format($data[0]['_total'], 'auto', false).''; $current_value = $data[0]['_total']; // we handle simple values } else { $a = getBooleanValues($indicator); $class= ''; if($a && ($indicator['sdii_nature'] == 'boolean' || $indicator['sdii_nature'] == 'qualitative')) { if(count($a) == 2) { if($result_value[0]['sdiv_value'] == 0) $class= " boolean-false"; else $class= " boolean-true"; } else $class = $class= " boolean-value-" . $result_value[0]['sdiv_value']; $current_value = $a[$result_value[0]['sdiv_value']]; $classbmask = ' boolean-mask'; } else { $classbmask = ''; $current_value = fnumber_format($result_value[0]['sdiv_value'], 'auto', false); } $str .= ''.$current_value.''; } $class=""; } $str .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); $str .= ''.formatText($indicator['sdii_unit']).''; $str .= '
    '; if(isset($result_value[0])) { $arr = array_reverse($result_value); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $str .= '
    ' . $lastyear . '
    '; } $str .= getTendency($result_value, $indicator); return $str; } } if(!function_exists('getSparklineViz')) { function getSparklineViz($sql_object, $scale_id, $indicator, $threshold_value) { // getting all values $req_sdiav=SQL_getAllValue("SCA", $scale_id, $indicator['sdii_id']); $result_value = $sql_object -> DBSelect($req_sdiav); $str = '
    '; // there is no value if ($result_value==false) { $str .= '-'; // some values are there } else { $data = array(); // we reverse the array to display eldest first $values = array_reverse($result_value); foreach($values as $value) { // we handle multivalues if(!empty($value['sdiv_multivalue'])) { $dataindic = unserialize($value['sdiv_multivalue']); array_push($data, $dataindic[0]['_total']); // we handle simple values } else { array_push($data, $value['sdiv_value']); } } $str .= '

    '.join(',',$data).'

    '; } $str .= '
    '; if(isset($result_value[0])) { $arr = array_reverse($result_value); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $str .= '
    ' . $lastyear . '
    '; } $str .= getTendency($result_value, $indicator); return $str; } } if(!function_exists('getViz')) { function getViz($sql_object, $scale_id, $indicator, $threshold_value, $overwrite = null, $cursorcssposition = 0) { if(!is_null($overwrite)) { $vizualisation_type = $overwrite; } else { $vizualisation_type = $indicator['sdii_dashboard_viz']; } if($vizualisation_type == 'raw') { $viz = getRawViz($sql_object, $scale_id, $indicator, $threshold_value); } if($vizualisation_type == 'gauge') { $viz = getGaugeViz($sql_object, $scale_id, $indicator, $threshold_value, $cursorcssposition); } if($vizualisation_type == 'sparkline') { $viz = getSparklineViz($sql_object, $scale_id, $indicator, $threshold_value, $cursorcssposition); } return $viz; } } /** * getBooleanValues() * Return boolean values enter in comment fields * or false if no mask is set or if not boolean * as {0=oui;1=non} format * @param array $indicator * @return mixed (false or array) */ if(!function_exists('getBooleanValues')) { function getBooleanValues($indicator) { if($indicator['sdii_nature'] == 'boolean' || $indicator['sdii_nature'] == 'qualitative') { // get content with the following pattern // For example {0=non signée;1=signée} $pattern = '/{(.*?)}/'; $r =preg_match($pattern, $indicator['sdii_comment'], $matches); if($r == 0) return false; $b = array(); $str = rtrim($matches[1], ";"); $a = explode(";", $str); foreach($a as $entry) { list($key, $value) = explode("=", $entry); $key = trim($key); $b[$key] = trim($value); } return $b; } return false; } } /** * getColorRamp() * @param array $values * @param array $colors * @return array $hexa_colors */ if(!function_exists('getColorRamp')) { function getColorRamp($values, $colors = array('1' => '#D73027', '2' => '#FFFFBF', '3' => '#1A9850')) { $hexa_colors = array (); // default colors taken from chroma 'RdYlGn' // https://github.com/gka/chroma.js/wiki/Predefined-Colors require_once ('../lib/vendor/PHP-Color/autoload.php'); // https://github.com/ProjectCleverWeb/PHP-Color/issues/4 // https://github.com/ProjectCleverWeb/PHP-Color/issues/3#issuecomment-255130522 /** * * GRADIENTS/SCALES ** */ $color1 = new projectcleverweb\color\main ( $colors ['1'] ); $color2 = new projectcleverweb\color\main ( $colors ['2'] ); $color3 = new projectcleverweb\color\main ( $colors ['3'] ); // ge number of classes $nb_values = count ( $values ); $nb_classes = ( int ) (count ( $values ) / 2); if ($nb_classes === 0) return false; // necessary to get number of wanted classes if ($nb_values % 2 == 1) $plus = 1; else $plus = 0; // print_r ( $values ); // Gradient array with a custom number of colors (offset 0 is $color1 and offset 9 is $color2) $gradient_array_1 = $color1->gradient ( $color2, ($nb_classes + $plus) ); // Gradient array with exactly enough non-duplicate colors $gradient_array_2 = $color1->gradient ( $color2 ); // You can't currently create a gradient with more than 2 colors, but you can merge 2+ gradient arrays $gradient_array_3 = $color2->gradient ( $color3, ($nb_classes + 1) ); array_shift ( $gradient_array_3 ); $gradient_array_4 = array_merge ( $gradient_array_1, $gradient_array_3 ); // print_r ( $gradient_array_4 ); foreach ( $values as $key => $value ) { // foreach ($gradient_array_4 as $key) { // we determine text color by contrat to background $o = round ( (($gradient_array_4 [$key] ['r'] * 299) + ($gradient_array_4 [$key] ['g'] * 587) + ($gradient_array_4 [$key] ['b'] * 114)) / 1000 ); if ($o > 125) $hexa_colors [$key] ['color'] = '000000'; else $hexa_colors [$key] ['color'] = 'ffffff'; $color = new projectcleverweb\color\main ( $gradient_array_4 [$key], 'RGB' ); $hexa = $color->hex (); // echo '
    '. $key.' #'.$hexa . '

    '; $hexa_colors [$key] ['background-color'] = $hexa; } return $hexa_colors; } } /** * getQualitativeViz() * Return global rate * @param array $values * @param array $indicator */ if(!function_exists('getQualitativeViz')) { function getQualitativeViz($values, $indicator, $dateFormat = 'short', $legend = true, $topdf = false) { // @todo implement PHP version require_once('../lib/vendor/PHP-Color/autoload.php'); // https://github.com/ProjectCleverWeb/PHP-Color/issues/4 // https://github.com/ProjectCleverWeb/PHP-Color/issues/3#issuecomment-255130522 // $o = new projectcleverweb\color\main('FF0000'); // $hex_scheme = $o->scheme('compound'); // print_r($hex_scheme); // test if there is record if(!isset($values[0]['sdiv_id'])) return false; // we retrieve values $a = getBooleanValues($indicator); // get get color ramp $colors = getColorRamp($a); if($a) { $index = array(); foreach ($a as $key => $value) { array_push($index, $key); } $minvalue = min($index); $maxvalue = max($index); // @todo to remove //footerAddJS('../lib/js/chroma.js/chroma.min.js'); // https://github.com/gka/chroma.js/wiki/Predefined-Colors $js = ' var viz_color = chroma.scale("RdYlGn").colors('.count($a).'); // http://jsfiddle.net/PXJ2C/ $("td.qualitative-value").each(function() { var val = $(this).attr("data-value"); $(this).css("background-color", viz_color[val]); var rgb = chroma(viz_color[val]).rgb(); var o = Math.round(((parseInt(rgb[0]) * 299) + (parseInt(rgb[1]) * 587) + (parseInt(rgb[2]) * 114)) /1000); if(o > 125) $(this).css("color", "black"); else $(this).css("color", "white"); });'; // footerAddInlineJS($js); } // print_r($values); $content = ''; $header = ''; $body = ''; $width = round(100 / count($values)); $values = $reversed = array_reverse($values); for ($i=0; $i '; $body .= ''. $a[$values[$i]['sdiv_value']] .''; } if($topdf == true) $content .= ''; $content .= '
    %s%s
    '; if($legend) { $legend = ''; if($topdf == false) $legendblock = ' '; else $legendblock = 'xxxx'; foreach ($a as $key => $value) { $legend .= ''.$legendblock.' '.$value.''; if($topdf == true) $legend .= ''.$legendblock.''; } $content .= '
    '.$legend.'
    '; } return sprintf($content, $header, $body); } } /** * getRates() * Return global rate and * @param array $indicator * @param numeric $firstValue * @param numeric $firstValue * @param integer $year_start * @param integer $year_end */ if(!function_exists('getRates')) { function getRates($firstValue, $lastValue, $year_start, $year_end, $format = 'html') { if((int) $year_start > (int) $year_end) $years = $year_start - $year_end; else $years = $year_end - $year_start; if($firstValue == 0) { $global_evol = empty_nc(''); $tcam = empty_nc(''); } else { // gobal rate $global_evol = (($lastValue - $firstValue) / $firstValue * 100); // tcam // $tcam = (pow ( (2349816 / 2339881) , 1/5 ) - 1) * 100; // doit retourner 0.085 % if($years > 1) $tcam = (pow ( ($lastValue / $firstValue) , 1 / $years ) - 1) * 100; else $tcam = empty_nc(''); } if($format == 'html') { return '
    ' . _t('dashboard', 'global_rate') . ' : ' . fnumber_format($global_evol, 2, false) . ' % | ' . _t('dashboard', 'cagr'). ' : ' . fnumber_format($tcam, 2, false) . ' %
    '; } else { return _t('dashboard', 'global_rate') . ' : ' . fnumber_format($global_evol, 2, false) . ' % | '. strip_tags(_t('dashboard', 'cagr')). ' : ' . fnumber_format($tcam, 2, false) . ' %'; } } } /** * getTendency() * Return indicator tendency based on value * (not based on performance) * @param array $values * @param array $indicator */ if(!function_exists('getTendency')) { function getTendency($values, $indicator) { $tendency = '
    '; $percentage = ''; $evolution = ''; // we handle multivalues // if there is a previous value if(!empty($values[1]['sdiv_multivalue'])) { $data = unserialize($values[0]['sdiv_multivalue']); $dataPlusOne = unserialize($values[1]['sdiv_multivalue']); if($indicator['sdii_nature'] == 'quantitative') { if($dataPlusOne[0]['_total'] != 0) { $percentage = ($data[0]['_total'] - $dataPlusOne[0]['_total']) / $dataPlusOne[0]['_total'] * 100; $evolution = ' ('.round($percentage, 0). '%)'; } else $evolution = ' ('.empty_nc(''). ' %)'; } if ($data[0]['_total'] > $dataPlusOne[0]['_total']) { $tendency.="\""._t('dashboard','value_tendance')."\""; } elseif($data[0]['_total'] < $dataPlusOne[0]['_total']) { $tendency.="\""._t('dashboard','value_tendance')."\""; } else { $tendency.="\""._t('dashboard','value_tendance')."\""; } // we handle simple values // if there is a previous value } elseif(isset($values[1]['sdiv_value'])) { $previous_value = fnumber_format($values[1]['sdiv_value'], 'auto', false); if($indicator['sdii_nature'] == 'quantitative') { if($values[1]['sdiv_value'] != 0) { $percentage = ($values[0]['sdiv_value'] - $values[1]['sdiv_value']) / $values[1]['sdiv_value'] * 100; $evolution = ' ('.round($percentage, 0). '%)'; } else $evolution = ' ('.empty_nc(''). ' %)'; } else { $a = getBooleanValues($indicator); if($a) { $index = array(); foreach ($a as $key => $value) { array_push($index, $key); } $previous_value = $a[$values[1]['sdiv_value']]; } } if ($values[0]['sdiv_value'] > $values[1]['sdiv_value']) { $tendency.="\""._t('dashboard','value_tendance')."\""; } elseif($values[0]['sdiv_value'] < $values[1]['sdiv_value']) { $tendency.="\""._t('dashboard','value_tendance')."\""; } else { $tendency.="\""._t('dashboard','value_tendance')."\""; } } else { $tendency .= ' '; } $tendency .= '
    '; return $tendency; } }