* @version $Id$ * @access public * @license http://opensource.org/licenses/gpl-3.0.html */ /** * unit_javascript_validation * @return void */ if(!function_exists('unit_javascript_validation')) { function unit_javascript_validation() { $js = '$("#min_value, #max_value, #threshold_value").change(function() { var minVal = $("#min_value").val().replace(",", "."); var maxVal = $("#max_value").val().replace(",", "."); var thresholdVal = $("#threshold_value").val().replace(",", "."); var dashboardViz = $("#sdi_dashboard_viz").find(":selected").val(); console.log("min : " + minVal + " - max : " + maxVal + " - threshold : " + thresholdVal); if(isNumeric(minVal) && isNumeric(maxVal) && maxVal <= minVal ) alertify.error("'._t("sdi","object_minmax_error").'"); // if thresold and min are provided, be sure thresold is superior to min if(isNumeric(minVal) && isNumeric(thresholdVal) && thresholdVal < minVal ) alertify.error("'._t("sdi","object_minthreshold_error").'"); // if thresold and max are provided, be sure thresold is inferior to max if(isNumeric(maxVal) && isNumeric(thresholdVal) && thresholdVal > maxVal ) alertify.error("'._t("sdi","object_maxthreshold_error").'"); // we add check if gauge if(dashboardViz == "gauge") { if(!isNumeric(maxVal) || !isNumeric(minVal) || !isNumeric(thresholdVal)) alertify.error("'.sprintf(_t('sdi','object_gauge_error1'), $GLOBALS['lang']['sdi']['select_dashboard_viz']['gauge']).'"); if(isNumeric(maxVal) && isNumeric(thresholdVal) && thresholdVal >= maxVal ) alertify.error("'.sprintf(_t('sdi','object_gauge_error2'), $GLOBALS['lang']['sdi']['select_dashboard_viz']['gauge']).'"); if(isNumeric(minVal) && isNumeric(thresholdVal) && thresholdVal <= minVal ) alertify.error("'.sprintf(_t('sdi','object_gauge_error3'), $GLOBALS['lang']['sdi']['select_dashboard_viz']['gauge']).'"); } });'; footerAddInlineJS($js); } } /** * get_unique_indicators * @param array $sdi * @param boolean $noorphan * @return array */ if(!function_exists('get_unique_indicators')) { function get_unique_indicators($sdi, $noorphan = false) { $uniques = []; $cnt = 0; if($noorphan) { $levelExclude = 0; } else { $levelExclude = -999; // wich has no effect } if(!is_array($sdi)) return array('indicators' => [], 'count' => 0); foreach ($sdi as $s) { if(!in_array($s['sdii_id'], $uniques) && $s['sdii_level'] != $levelExclude) { array_push($uniques, $s['sdii_id']); $cnt++; } } return array('indicators' => $uniques, 'count' => $cnt); } } /** * _get_results_attributes * @param array $json_arr * @return array * @todo @simo remove ? - not used */ if(!function_exists('_get_results_attributes')) { function _get_results_attributes(array $json_arr) { $a = []; // we set array key we have to iterate from // opendatasoft : 'results' // koumoul (default query type) : 'results' // arcgis : 'features' + attributes field in loop if(isset($json_arr['features'])) { $a['main_field'] = 'features'; $a['sec_field'] = 'attributes'; } if(isset($json_arr['results'])) $a['main_field'] = 'results'; return $a; } } /** * _format_results * Format results all the same way, whatever it comes from distinct API with different formats * Resulting array is like so : array('results' => array(0 => array( 'value' => 100, 'date' => '2022', 'something' => 'xxx'), 1 => array( 'value' => 100, 'date' => '2022', 'something' => 'xxx')); * @param array $json_arr * @return array */ if(!function_exists('_format_results')) { function _format_results(array $json_arr) { $a = []; // arcgis : 'features' + 'attributes' field in loop // geoserver : 'features' + 'properties' field in loop if(isset($json_arr['features'])) { $tmp = []; foreach ($json_arr['features'] as $rec) { if(isset($rec['attributes'])) array_push($tmp, $rec['attributes']); // arcgis if(isset($rec['properties'])) array_push($tmp, $rec['properties']); // geoserver } $a['results'] = $tmp; } // opendatasoft and koumoul (default query type) : 'results' if(isset($json_arr['results'])) $a = $json_arr; // @todo for koumoul aggregation see : https://data.ademe.fr/data-fair/api/v1/datasets/investissements-d'avenir-projets/values_agg?field=Code_EPCI&format=json&metric=sum&metric_field=Co%C3%BBt_total_du_projet&agg_size=99&qs=Code_EPCI%3A%22200018166%22&size=99&select=Total_autoris%C3%A9%2CCo%C3%BBt_total_du_projet%2CCode_EPCI // print_r($a); return $a; } } /** * api_update_indicators * @param array $sdi * @param boolean $initialImport * @return boolean */ if(!function_exists('api_update_indicators')) { function api_update_indicators($sdi, $initialImport = false) { global $sql_object; $debug = false; $scale_id = 1; # https://docs.guzzlephp.org/en/5.3/quickstart.html // use GuzzleHttp\Client; // $client = new Client(); // @see https://stackoverflow.com/questions/20847633/limit-connecting-time-with-guzzle-http-php-client // we add a timeout to client not to block script $client = new GuzzleHttp\Client(['timeout' => 3, 'connect_timeout' => 3]); foreach ($sdi as $indicator) { // if API is enabled only if($indicator['sdii_api_enabled'] == 'Y') { // initial import, we set given year if passed if($initialImport) { if(!empty($indicator['sdii_api_getvalues-since'])) $since = $indicator['sdii_api_getvalues-since']; else $since='1900'; // we fake the date to import everything } // $sql_object -> DBQuery("DELETE FROM l21_sdi_value WHERE sdiv_sdi_info ='" . $indicator['sdii_id'] . "' AND sdiv_scale ='" .$scale_id."'"); // we select last entered values and compare with frequency to see if we have to execute update routine or not // for all cases (even initial import) - if set, we get the latest indicator value and date for the given scale $lastV = $sql_object -> DBSelect(SQL_getlastInsertByPublicationDate($indicator['sdii_id'], $scale_id)); // if exists, it can override $since variable to prevent multiple imports on initial import - security if(isset($lastV[0]['sdiv_value']) ) $since = $lastV[0]['sdiv_date_published']; // we get threshold from old values or default value, if null, replacing by empty string if(isset($lastV[0]['sdiv_value']) && !is_null($lastV[0]['sdiv_threshold'])) { $threshold = $lastV[0]['sdiv_threshold']; } else { if(is_numeric($indicator['sdii_threshold_value'])) $threshold = $indicator['sdii_threshold_value']; else $threshold = ''; } // we check if url is responding, if not we log the error try { $response = $client->get($indicator['sdii_api_url']); $code = $response->getStatusCode(); // no test on $indicator['sdii_api_getvalues'] == 'Y', because it is supposed to be done before calling the function if($code == '200') { // we convert json response to array $records = json_decode($response->getBody(), true); // print_r($records); // we set fields structures, based on resulting json file // $attrs = _get_results_attributes($records); // @todo @simo remove ? - not used // we format retrieved json file if needed $records = _format_results($records); // foreach ($records[$attrs['main_field']] as $rec) { // @todo @simo remove ? - not used foreach ($records['results'] as $rec) { //if(isset($rec[$attrs['sec_field']])) $rec = $rec[$attrs['sec_field']]; // @todo @simo remove ? - not used if($debug) print_r($rec); $format = "Y-m-d"; // date object format // we create date object for comparison // if only year is passed, we add month and day and create the object if(strlen($rec[$indicator['sdii_api_datefield']]) == 4) { $rec[$indicator['sdii_api_datefield']] .= '-12-31'; $recordDate = DateTime::createFromFormat($format, $rec[$indicator['sdii_api_datefield']]); // else default format is similar to : "2012-01-01T00:00:00+00:00" } else { $recordDate = new DateTime($rec[$indicator['sdii_api_datefield']]); } // we create a formatted date for display $formattedDate = $recordDate->format("Y-m-d"); // Output format : 2023-06-04 // only year is passed to since, we add month and day if(strlen($since) == 4) $since .= '-01-01'; // we get last date $lastvalue = DateTime::createFromFormat($format, $since); $formattedLastvalue = $lastvalue->format("Y-m-d"); // we add interval to latest retrieved date $triggerDate = $lastvalue; $triggerDate->modify('+' . $indicator['sdii_frequency'] . 'days'); // we finally compare $triggerDate with $recordDate to check if we have to add records in database if($debug) echo "

Indicator id : ".$indicator['sdii_id'] ." [comparison] current record : " . $formattedDate . ' / last value: ' . $formattedLastvalue . " / trigger date : " . $triggerDate->format("Y-m-d") . '

'; if($recordDate >= $triggerDate) { if($debug) echo ">> AJOUT
"; if(isset($rec[$indicator['sdii_api_valuefield']]) && isset($rec[$indicator['sdii_api_datefield']])) { $a = []; $a[0] = sys_number_format(round($rec[$indicator['sdii_api_valuefield']], $indicator['sdii_api_decimal'])); // value $a[1] = $indicator['sdii_id']; // indicator id $a[2] = $threshold; $a[3] = $scale_id; // scale id $a[4] = $formattedDate; // date (format yyyy-mm-dd) $a[5] = 'p'; // status $a[6] = _t('sdi', 'api-retrieved'); // comment $a[7] = 'N'; // comment status $a['user_id'] = 1; if($debug) echo '
'; if($debug) print_r($a); if($debug) echo '
'; $sdio = new sdi; $integrity = $sdio->CheckDataIntegrity_value($a, $sql_object); if(!is_string($integrity)) { $r = $sdio->AddValue($a, $sql_object); if(is_numeric($r)) logfile(LOG_MAINFILE, array('[API call]', 'SUCCESS - adding values to db', 'indicator : ' . $indicator['sdii_id'], 'added value ID : '. $r)); } else { // CheckDataIntegrity_value failed logfile(LOG_MAINFILE, array('[API call]', 'ERROR - CheckDataIntegrity_value() failed', 'indicator : ' . $indicator['sdii_id'], $indicator['sdii_api_url'], 'error message : '. strip_tags((string) $integrity))); return false; } } else { // given keys are inconsistent logfile(LOG_MAINFILE, array('[API call]', 'ERROR - given array keys are inconsistents : ' . $indicator['sdii_api_valuefield'] . ' / "'. $indicator['sdii_api_datefield']. ' - check url result and change fields values', 'indicator : ' . $indicator['sdii_id'], $indicator['sdii_api_url'])); return false; } } } } // if 404 exception is caught - others errors as well } catch (Exception $e) { logfile(LOG_MAINFILE, array('[API call]', 'URL not responding', $indicator['sdii_api_url'], 'indicator : ' . $indicator['sdii_id'], $e->getMessage())); return false; } } // closing $indicator['sdii_api_enabled'] == 'Y' test } return true; } } 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:";", callback:compute_values});'); // 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)]; } else { $display_min = '[WARNING] no min/max defined for boolean / qualitative indicator'; $display_max = '[WARNING] no min/max defined for boolean / qualitative indicator'; 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'])); } } if(!empty($threshold_value)) $display_threshold = $a[$threshold_value]; else $display_threshold = empty_nc(''); } $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, $indicatorValues, $cursorcssposition) { if($indicator['sdii_multiple_type'] == 'sum') $cfield = '_total'; if($indicator['sdii_multiple_type'] == 'mean') $cfield = '_mean'; // values are stored if ($indicatorValues <> false) { // we handle multivalues if(!empty($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $current_value = $data[0][$cfield]; // we handle simple values } else { $current_value = $indicatorValues[0]['sdiv_value']; } $value_cursor1 = getPositionfromValue ($current_value, $indicator, $threshold_value); // 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 ($indicatorValues == 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'; if(!empty($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $current_value = $data[0][$cfield]; } else $current_value = $indicatorValues[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($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $current_value = $data[0][$cfield]; // we handle simple values } else { $current_value = $indicatorValues[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);"; $listing = "
    "; $listing .= "
    "; $listing .= "
    "; // $listing .= "\"\""; $listing .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); $listing .= "
    "; if(isset($indicatorValues[0])) { $arr = array_reverse($indicatorValues); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $listing .= '
    ' . $lastyear . '
    '; } $listing .= getTendency($indicatorValues, $indicator); // $listing .= "\t (".strtolower(fnumber_format($current_value, 'auto', false)).")\n"; return $listing; } } if(!function_exists('getSimpleViz')) { function getSimpleViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues) { $str = '
    '; // there is no value if ($indicatorValues == false) { $str .= '-'; $current_value = _t('dashboard', 'novalue'); $class = "indicator-no-data"; // some values are there } else { // we handle multivalues if (!empty($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $str .= '' . _t('sdi', 'multiple_type_none'). ''; $current_value = _t('sdi', 'multiple_type_none'); } $class = ""; } $str .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); $str .= '' . formatText($indicator['sdii_unit']) . ''; $str .= '
    '; if (isset($indicatorValues[0])) { $arr = array_reverse($indicatorValues); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $str .= '
    ' . $lastyear . '
    '; } $str .= getTendency($indicatorValues, $indicator); return $str; } } if(!function_exists('getRawViz')) { function getRawViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues) { if($indicator['sdii_multiple_type'] == 'sum') $cfield = '_total'; if($indicator['sdii_multiple_type'] == 'mean') $cfield = '_mean'; if($indicator['sdii_multiple_type'] == 'none') $cfield = '_none'; $str = '
    '; // there is no value if ($indicatorValues==false) { $str .= '-'; $current_value = _t('dashboard','novalue'); $class="indicator-no-data"; // some values are there } else { // we handle multivalues if(!empty($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $str .= ''.fnumber_format($data[0][$cfield], 2, false).''; $current_value = $data[0][$cfield]; // we handle simple values } else { $a = getBooleanValues($indicator); $class= ''; if($a && ($indicator['sdii_nature'] == 'boolean' || $indicator['sdii_nature'] == 'qualitative')) { if(count($a) == 2) { if($indicatorValues[0]['sdiv_value'] == 0) $class= " boolean-false"; else $class= " boolean-true"; } else $class = $class= " boolean-value-" . $indicatorValues[0]['sdiv_value']; $current_value = $a[$indicatorValues[0]['sdiv_value']]; $classbmask = ' boolean-mask'; } else { $classbmask = ''; $current_value = fnumber_format($indicatorValues[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($indicatorValues[0])) { $arr = array_reverse($indicatorValues); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $str .= '
    ' . $lastyear . '
    '; } $str .= getTendency($indicatorValues, $indicator); return $str; } } if(!function_exists('getSparklineViz')) { function getSparklineViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues) { if($indicator['sdii_multiple_type'] == 'sum') $cfield = '_total'; if($indicator['sdii_multiple_type'] == 'mean') $cfield = '_mean'; // we handle multivalues if(!empty($indicatorValues[0]['sdiv_multivalue'])) { $data = unserialize($indicatorValues[0]['sdiv_multivalue']); $current_value = fnumber_format($data[0][$cfield], 2, false); // we handle simple values } else { if($indicatorValues == false) $current_value = _t('dashboard','novalue'); else $current_value = $indicatorValues[0]['sdiv_value']; } $str = '
    '; // there is no value if ($indicatorValues==false) { $str .= '-'; $class="indicator-no-data"; // some values are there } else { $data = array(); $class = ''; // we reverse the array to display eldest first $values = array_reverse($indicatorValues); foreach($values as $value) { // we handle multivalues if(!empty($value['sdiv_multivalue'])) { $dataindic = unserialize($value['sdiv_multivalue']); array_push($data, $dataindic[0][$cfield]); // we handle simple values } else { array_push($data, $value['sdiv_value']); } } $str .= '

    '; $str .= ''.join(',',$data).''; $str .= getIndicatorInfoBox($current_value, $indicator, $threshold_value, $class); $str .= '

    '; } $str .= '
    '; if(isset($indicatorValues[0])) { $arr = array_reverse($indicatorValues); $lastval = end($arr); $lastyear = get_year($lastval['date_p']); $str .= '
    ' . $lastyear . '
    '; } $str .= getTendency($indicatorValues, $indicator); return $str; } } if(!function_exists('getViz')) { function getViz($sql_object, $scale_id, $indicator, $threshold_value, $overwrite = null, $cursorcssposition = 0) { $req_sdiav=SQL_getAllValue("SCA", $scale_id, $indicator['sdii_id']); $indicatorValues = $sql_object -> DBSelect($req_sdiav); if(!is_null($overwrite)) { $vizualisation_type = $overwrite; } else { $vizualisation_type = $indicator['sdii_dashboard_viz']; } // we overwrite vizualisation type if $indicator['sdii_multiple_type'] == 'none' if($indicator['sdii_value_type'] == 'multiple' && $indicator['sdii_multiple_type'] == 'none') $vizualisation_type = 'simple'; // we override sparkline viz if one value only because it is not readable by user if($vizualisation_type == 'sparkline' && is_array($indicatorValues) && count($indicatorValues) == 1) $vizualisation_type = 'raw'; if($vizualisation_type == 'raw') { $viz = getRawViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues); } if($vizualisation_type == 'gauge') { $viz = getGaugeViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues, $cursorcssposition); } if($vizualisation_type == 'sparkline') { $viz = getSparklineViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues); } if($vizualisation_type == 'simple') { $viz = getSimpleViz($sql_object, $scale_id, $indicator, $threshold_value, $indicatorValues); } 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) { if($indicator['sdii_multiple_type'] == 'sum') $cfield = '_total'; if($indicator['sdii_multiple_type'] == 'mean') $cfield = '_mean'; if($indicator['sdii_multiple_type'] == 'none') $cfield = '_none'; $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' && $indicator['sdii_multiple_type'] != 'none') { if($dataPlusOne[0][$cfield] != 0) { $percentage = ($data[0][$cfield] - $dataPlusOne[0][$cfield]) / $dataPlusOne[0][$cfield] * 100; $evolution = ' ('.round($percentage, 0). '%)'; } else $evolution = ' ('.empty_nc(''). ' %)'; } if($indicator['sdii_multiple_type'] == 'none') $tendency.= ''; else { if ($data[0][$cfield] > $dataPlusOne[0][$cfield]) { $tendency .= "\"""; } elseif ($data[0][$cfield] < $dataPlusOne[0][$cfield]) { $tendency .= "\"""; } else { $tendency .= "\"""; } } // 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; } }