From: Maxious Date: Fri, 22 Jul 2011 17:47:22 +0000 Subject: Improve BubbleTree colors X-Git-Url: http://maxious.lambdacomplex.org/git/?p=contractdashboard.git&a=commitdiff&h=44a32a705d3f6dc4021ed0fdf4f594f05371fb37 --- Improve BubbleTree colors --- --- /dev/null +++ b/.gitmodules @@ -1,1 +1,4 @@ +[submodule "lib/bubbletree"] + path = lib/bubbletree + url = https://github.com/okfn/bubbletree.git --- a/admin/displayUNSPSC.php +++ b/admin/displayUNSPSC.php @@ -1,11 +1,7 @@ "; while ($row = mysql_fetch_assoc($catsresult)) { $catName = $unspsc[$row['cat']."000000"].$row['cat']; - if ($row['cat'] = "") $catName = "null"; + if ($row['cat'] == "") $catName = "null"; echo "$catName".$row['value'].""; } --- /dev/null +++ b/displayBubbletree.php @@ -1,1 +1,109 @@ + + + + + Minimal BubbleTree Demo + + + + + + + + + + + + + +
+
+
+ + + --- a/heuristics/dateHeuristics.php +++ b/heuristics/dateHeuristics.php @@ -20,27 +20,32 @@ $averageContractPeriod; function getAverageContractPeriod() { - global $averageContractPeriod; + global $averageContractPeriod, $stddevContractPeriod; if (!$averageContractPeriod) { - $query = "select AVG(dateDiff(contractEnd,contractStart)) from contractnotice"; - $result = mysql_query($query); - $r = mysql_fetch_array($result, MYSQL_BOTH); - $averageContractPeriod = $r[0]; + getStddevAverageContractPeriod(); } return $averageContractPeriod; } $stddevContractPeriod; function getstddevContractPeriod() { - global $stddevContractPeriod; + global $averageContractPeriod, $stddevContractPeriod; if (!$stddevContractPeriod) { - $query = "select STDDEV(dateDiff(contractEnd,contractStart)) from contractnotice"; - $result = mysql_query($query); - $r = mysql_fetch_array($result, MYSQL_BOTH); - $stddevContractPeriod = $r[0]; + getStddevAverageContractPeriod(); } return $stddevContractPeriod; } +function getStddevAverageContractPeriod() +{ + global $averageContractPeriod, $stddevContractPeriod; + $query = "select AVG(dateDiff(contractEnd,contractStart)),stddev(dateDiff(contractEnd,contractStart)) from contractnotice"; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $averageContractPeriod = $r[0]; + $stddevContractPeriod = $r[1]; +} + + //Reported late, 45 days? A late contract is a dodgy contract except maybe for variations? $heuristics["DATE_REPORTED_LATE"] = Array( "description" => "Reported late, 45 days?" @@ -70,10 +75,7 @@ { global $averageDaysLate; if (!$averageDaysLate) { - $query = "select AVG(dateDiff(publishDate,contractStart)) from contractnotice"; - $result = mysql_query($query); - $r = mysql_fetch_array($result, MYSQL_BOTH); - $averageDaysLate = $r[0]; + getDaysLate(); } return $averageDaysLate; } @@ -82,11 +84,19 @@ { global $stddevDaysLate; if (!$stddevDaysLate) { - $query = "select STDDEV(dateDiff(publishDate,contractStart)) from contractnotice"; - $result = mysql_query($query); - $r = mysql_fetch_array($result, MYSQL_BOTH); - $stddevDaysLate = $r[0]; + getDaysLate(); } return $stddevDaysLate; } +function getDaysLate() { + + global $averageDaysLate,$stddevDaysLate; + + $query = "select AVG(dateDiff(publishDate,contractStart)), STDDEV(dateDiff(publishDate,contractStart)) from contractnotice"; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $averageDaysLate = $r[0]; + $stddevDaysLate = $r[1]; + +} ?> --- a/heuristics/heuristics.inc.php +++ b/heuristics/heuristics.inc.php @@ -1,20 +1,25 @@ \n"; - elseif (strpos(mysql_error() , "Duplicate entry") === false) echo $hresults . " failed insert.
" . mysql_error() . "
$query

\n"; + // save value and cn data via sql + $result = mysql_query($query); + if ($result) echo "Saved $heuristicName for {$cn["CNID"]}
\n"; + elseif (strpos(mysql_error() , "Duplicate entry") === false) echo $hresults . " failed insert.
" . mysql_error() . "
$query

\n"; + } } ?> + --- a/heuristics/historyHeuristics.php +++ b/heuristics/historyHeuristics.php @@ -1,25 +1,126 @@ - "unusual for agency/supplier due to previous low number of transactions " + "unusual for agency due to previous low number of transactions " ); -function HISTORY_LOW_TRANSACTIONS($cn) +function HISTORY_LOW_TRANSACTIONS_AGENCY($cn) { - $averageContractPeriod = getAverageContractPeriod(); - $diff = strtotime($cn['contractStart']) - strtotime($cn['publishDate']); - $days = intval($diff / 24); - return ($days > 45 ? 1 : 0); + $thisAgencyTransactions = getAgencyTransactions($cn['agencyName']); + $averageAgencyTransactions = getAverageAgencyTransactions(); + $stddevAgencyTransactions = getstddevAgencyTransactions(); + $diff = strtotime($cn['contractEnd']) - strtotime($cn['contractStart']); + $days = intval($diff / (60 * 60 * 24)); + $value = abs($days - $averageAgencyTransactions) / $stddevAgencyTransactions; + return Array( + "heuristic_value" => $value, + "raw_value" => $days, + "mean" => $averageAgencyTransactions, + "stddev" => $stddevAgencyTransactions + ); } - /* - unusual value for time of year - - compare to all other records in last 2 weeks - - ie. many large contracts in june so takes more to standout*/ - - $heuristics["HISTORY_HIGH_VALUE_FOR_MONTH"] = Array( - "description" => "unusual value for time of year"); -function HISTORY_HIGH_VALUE_FOR_MONTH($cn) +$agencyTransactions = Array(); +function getAgencyTransactions($agencyName) { - $averageContractPeriod = getAverageContractPeriod(); - $diff = strtotime($cn['contractStart']) - strtotime($cn['publishDate']); - $days = intval($diff / 24); - return ($days > 45 ? 1 : 0); + global $agencyTransactions; + if (!$agencyTransactions[$agencyName]) { + $query = 'select count(*) from contractnotice where agencyName = "' . $agencyName . '"'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $agencyTransactions[$agencyName] = $r[0]; + } + return $agencyTransactions[$agencyName]; } +$averageAgencyTransactions; +function getAverageAgencyTransactions() +{ + global $averageAgencyTransactions; + if (!$averageAgencyTransactions) { + getStatsAgencyTransactions(); + } + return $averageAgencyTransactions; +} +$stddevAgencyTransactions; +function getstddevAgencyTransactions() +{ + global $stddevAgencyTransactions; + if (!$stddevAgencyTransactions) { + getStatsAgencyTransactions(); + } + return $stddevAgencyTransactions; +} +function getStatsAgencyTransactions() +{ + global $averageAgencyTransactions, $stddevAgencyTransactions; + $query = "select avg(count), STDDEV(count) from (select count(*) as count + from contractnotice group by agencyName) as a;"; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $averageAgencyTransactions = $r[0]; + $stddevAgencyTransactions = $r[1]; +} +$heuristics["HISTORY_LOW_TRANSACTIONS_SUPPLIER"] = Array( + "description" => "unusual for supplier due to previous low number of transactions " +); +function HISTORY_LOW_TRANSACTIONS_SUPPLIER($cn) +{ + $thisSupplierTransactions = getSupplierTransactions($cn['supplierName'], $cn['supplierABN']); + $averageSupplierTransactions = getAverageSupplierTransactions(); + $stddevSupplierTransactions = getstddevSupplierTransactions(); + $diff = strtotime($cn['contractEnd']) - strtotime($cn['contractStart']); + $days = intval($diff / (60 * 60 * 24)); + $value = abs($days - $averageSupplierTransactions) / $stddevSupplierTransactions; + return Array( + "heuristic_value" => $value, + "raw_value" => $days, + "mean" => $averageSupplierTransactions, + "stddev" => $stddevSupplierTransactions + ); +} +$supplierTransactions = Array(); +function getSupplierTransactions($supplierName, $supplierABN) +{ + global $supplierTransactions; + if ($supplierABN != 0 && $supplierABN != "") { + if (!$supplierTransactions[$supplierABN]) { + $query = 'select count(*) from contractnotice where supplierABN = "' . $supplierABN . '"'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $supplierTransactions[$supplierABN] = $r[0]; + } + return $supplierTransactions[$supplierABN]; + } + if (!$supplierTransactions[$supplierName]) { + $query = 'select count(*) from contractnotice where supplierName = "' . $supplierName . '"'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $supplierTransactions[$supplierName] = $r[0]; + } + return $supplierTransactions[$supplierName]; +} +$averageSupplierTransactions; +function getAverageSupplierTransactions() +{ + global $averageSupplierTransactions; + if (!$averageSupplierTransactions) { + getStatsSupplierTransactions(); + } + return $averageSupplierTransactions; +} +$stddevSupplierTransactions; +function getstddevSupplierTransactions() +{ + global $stddevSupplierTransactions; + if (!$stddevSupplierTransactions) { + getStatsSupplierTransactions(); + } + return $stddevSupplierTransactions; +} +function getStatsSupplierTransactions() +{ + global $averageSupplierTransactions, $stddevSupplierTransactions; + $query = 'select avg(count), stddev(count) from (select IF(supplierABN != "",supplierABN,supplierName) as supplierID, count(*) as count from contractnotice group by supplierID) as a;'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $averageSupplierTransactions = $r[0]; + $stddevSupplierTransactions = $r[1]; +} + --- a/heuristics/metadataHeuristics.php +++ b/heuristics/metadataHeuristics.php @@ -1,12 +1,59 @@ "unusual value for time of year"); +/* all + SELECT description, count(*) as count +FROM `contractnotice` +group by description having count > 1 order by count +*/ +/*- duplicated description + - most duplicated overall, most duplicated per agency/category/supplier etc. */ +$heuristics["METADATA_DUPLICATED_DESCRIPTION"] = Array( + "description" => "" +); function METADATA_DUPLICATED_DESCRIPTION($cn) { - $averageContractPeriod = getAverageContractPeriod(); - $diff = strtotime($cn['contractStart']) - strtotime($cn['publishDate']); - $days = intval($diff / 24); - return ($days > 45 ? 1 : 0); + $averageDuplicatedDescriptions = getAverageDuplicatedDescriptions(); + $stddevDuplicatedDescriptions = getstddevDuplicatedDescriptions(); + $query = 'select count(*) from contractnotice where description = "' . $agencyName . '"'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $dupeDesc = $r[0]; + if ($dupeDesc == 1) $value = 0; + else $value = abs($dupeDesc - $averageDuplicatedDescriptions) / $stddevDuplicatedDescriptions; + return Array( + "heuristic_value" => $value, + "raw_value" => $dupeDesc, + "mean" => $averageDuplicatedDescriptions, + "stddev" => $stddevDuplicatedDescriptions + ); } +$averageDuplicatedDescriptions; +function getAverageDuplicatedDescriptions() +{ + global $averageDuplicatedDescriptions; + if (!$averageDuplicatedDescriptions) { + getStatsDuplicatedDescriptions(); + } + return $averageDuplicatedDescriptions; +} +$stddevDuplicatedDescriptions; +function getstddevDuplicatedDescriptions() +{ + global $stddevDuplicatedDescriptions; + if (!$stddevDuplicatedDescriptions) { + getStatsDuplicatedDescriptions(); + } + return $stddevDuplicatedDescriptions; +} +function getStatsDuplicatedDescriptions() +{ + $query = "select avg(count),STDDEV(count) from ( + SELECT description, count(*) as count +FROM `contractnotice` +group by description having count > 1 + ) as a;"; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $averageDuplicatedDescriptions = $r[0]; + $stddevDuplicatedDescriptions = $r[1]; +} + --- a/heuristics/runHeuristics.php +++ b/heuristics/runHeuristics.php @@ -7,7 +7,7 @@ FROM contractnotice JOIN agency ON contractnotice.agencyName=agency.agencyName WHERE DATE(importDate) = (select * from (SELECT DATE(importDate) FROM contractnotice ORDER BY importDate DESC limit 1) alias)"; -$result = mysql_query($lastimportquery); +$result = mysql_query($query); if (!$result) echo mysql_error().$query; while ($cn = mysql_fetch_array($result, MYSQL_BOTH)) { //get each new CN from latest update --- a/heuristics/valueHeuristics.php +++ b/heuristics/valueHeuristics.php @@ -1,8 +1,8 @@ - - - large contract value - - chi-square test for outliers / standard dev from mean/median - - percent of total contracts for supplier/agency - $heuristics["METADATA_DUPLICATED_DESCRIPTION"] = Array( + "unusual value for time of year"); function METADATA_DUPLICATED_DESCRIPTION($cn) { @@ -12,12 +12,15 @@ return ($days > 45 ? 1 : 0); } - - peculiar value + /* - peculiar value - Just under 80k, amplified if other contracts with same supplier are just under - - unusual variation amount - - absolute value; large reductions as well as large increases - - $heuristics["METADATA_DUPLICATED_DESCRIPTION"] = Array( + */ + $heuristics["VALUE_NEAR_THRESHOLD"] = Array( + "description" => "unusual value for time of year"); + /* + - unusual variation amount - absolute value; large reductions as well as large increases + */ + $heuristics["VALUE_LARGE_VARIATION"] = Array( "description" => "unusual value for time of year"); function METADATA_DUPLICATED_DESCRIPTION($cn) { @@ -26,3 +29,30 @@ $days = intval($diff / 24); return ($days > 45 ? 1 : 0); } + +/* - unusual value for time of year + - compare to all other records in last 2 weeks + - ie. many large contracts in june so takes more to standout*/ +$heuristics["VALUE_HIGH_FOR_MONTH"] = Array( + "description" => "unusual value for time of year" +); +function VALUE_HIGH_FOR_MONTH($cn, $monthAsInt) +{ + $averageContractPeriod = getAverageContractPeriod(); + $diff = strtotime($cn['contractStart']) - strtotime($cn['publishDate']); + $days = intval($diff / 24); + return ($days > 45 ? 1 : 0); +} +$monthlyValueAverage = Array(); +function getAgencyTransactions($agencyName) +{ + global $agencyTransactions; + if (!$agencyTransactions[$agencyName]) { + $query = 'select count(*) from contractnotice where agencyName = "' . $agencyName . '"'; + $result = mysql_query($query); + $r = mysql_fetch_array($result, MYSQL_BOTH); + $agencyTransactions[$agencyName] = $r[0]; + } + return $agencyTransactions[$agencyName]; +} +?> --- a/heuristics/viewHeuristicsColormap.php +++ b/heuristics/viewHeuristicsColormap.php @@ -1,5 +1,11 @@ + div { + padding: 5px; + display: inline-block; + } + '; // http://www.herethere.net/~samson/php/color_gradient/color_gradient_generator.php.txt // return the interpolated value between pBegin and pEnd function interpolate($pBegin, $pEnd, $pStep, $pMax) @@ -42,13 +48,13 @@ $maxVal = $r[0]; $query = "SELECT sum(heuristic_value) as sum, CNID -FROM `heuristic_results` group by CNID order by sum DESC LIMIT 30"; +FROM `heuristic_results` group by CNID order by sum DESC LIMIT 300"; $result = mysql_query($query); if (!$result) echo mysql_error().$query; while ($r = mysql_fetch_array($result, MYSQL_BOTH)) { - echo ''; + echo '
'; echo 'X'; - echo ""; + echo "
"; } ?> --- a/heuristics/viewHeuristicsDistribution.php +++ b/heuristics/viewHeuristicsDistribution.php @@ -14,22 +14,32 @@ include("../lib/pChart2.1.0/class/pData.class.php"); include("../lib/pChart2.1.0/class/pDraw.class.php"); include("../lib/pChart2.1.0/class/pImage.class.php"); -$labels = Array(); -$values = Array(); + +$series = Array(); include_once("../lib/common.inc.php"); -$query = "select floor(sum) as val,count(*) from (SELECT sum(heuristic_value) -as sum FROM heuristic_results group by CNID) as a group by val"; +$query = "select heuristic_name, floor(heuristic_value) as val,count(*) from heuristic_results group by heuristic_name, val"; $result = mysql_query($query); if (!$result) echo mysql_error().$query; while ($r = mysql_fetch_array($result, MYSQL_BOTH)) { - $labels[] = $r[0]; - $values[] = $r[1]; + $series[$r["heuristic_name"]][$r["val"]] = $r[2]; } /* Create and populate the pData object */ - $MyData = new pData(); - $MyData->addPoints($values,"Records"); + $MyData = new pData(); + $labels = Array(); + foreach ($series as $value) { + $labels = $labels+array_keys($value); + } + $labels = Array(0,1,2,3,4,5); +foreach ($series as $seriesName => $seriesEntry) { + $data; + foreach ($labels as $label) { + $data[$label] = ($seriesEntry[$label] ? $seriesEntry[$label] : 0); + } + +$MyData->addPoints($data,$seriesName); + } $MyData->setAxisName(0,"# of records"); $MyData->addPoints($labels,"Labels"); $MyData->setSerieDescription("Labels","Bins"); @@ -65,7 +75,7 @@ $myPicture->drawSplineChart(); /* Write the chart legend */ - $myPicture->drawLegend(540,20,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_HORIZONTAL)); + $myPicture->drawLegend(540,20,array("Style"=>LEGEND_NOBORDER,"Mode"=>LEGEND_VERTICAL)); /* Render the picture (choose the best way) */ $myPicture->autoOutput("pictures/example.drawSplineChart.simple.png"); --- /dev/null +++ b/lib/Color.php @@ -1,1 +1,502 @@ - + + * + * @license http://www.opensource.org/licenses/bsd-license.php BSD License + * + * @version $Id$ + * + */ +class Lux_Color +{ + /** + * + * Converts hexadecimal colors to RGB. + * + * @param string $hex Hexadecimal value. Accepts values with 3 or 6 numbers, + * with or without #, e.g., CCC, #CCC, CCCCCC or #CCCCCC. + * + * @return array RGB values: 0 => R, 1 => G, 2 => B + * + */ + public function hex2rgb($hex) + { + // Remove #. + if (strpos($hex, '#') === 0) { + $hex = substr($hex, 1); + } + + if (strlen($hex) == 3) { + $hex .= $hex; + } + + if (strlen($hex) != 6) { + return false; + } + + // Convert each tuple to decimal. + $r = hexdec(substr($hex, 0, 2)); + $g = hexdec(substr($hex, 2, 2)); + $b = hexdec(substr($hex, 4, 2)); + + return array($r, $g, $b); + } + + /** + * + * Converts hexadecimal colors to HSV. + * + * @param string $hex Hexadecimal value. Accepts values with 3 or 6 numbers, + * with or without #, e.g., CCC, #CCC, CCCCCC or #CCCCCC. + * + * @return array HSV values: 0 => H, 1 => S, 2 => V + * + */ + public function hex2hsv($hex) + { + return $this->rgb2hsv($this->hex2rgb($hex)); + } + + /** + * + * Converts hexadecimal colors to HSL. + * + * @param string $hex Hexadecimal value. Accepts values with 3 or 6 numbers, + * with or without #, e.g., CCC, #CCC, CCCCCC or #CCCCCC. + * + * @return array HSL values: 0 => H, 1 => S, 2 => L + * + */ + public function hex2hsl($hex) + { + return $this->rgb2hsl($this->hex2rgb($hex)); + } + + /** + * + * Converts RGB colors to hexadecimal. + * + * @param array $rgb RGB values: 0 => R, 1 => G, 2 => B + * + * @return string Hexadecimal value with six digits, e.g., CCCCCC. + * + */ + public function rgb2hex($rgb) + { + if(count($rgb) < 3) { + return false; + } + + list($r, $g, $b) = $rgb; + + // From php.net. + $r = 0x10000 * max(0, min(255, $r)); + $g = 0x100 * max(0, min(255, $g)); + $b = max(0, min(255, $b)); + + return strtoupper(str_pad(dechex($r + $g + $b), 6, 0, STR_PAD_LEFT)); + } + + /** + * + * Converts RGB to HSV. + * + * @param array $rgb RGB values: 0 => R, 1 => G, 2 => B + * + * @return array HSV values: 0 => H, 1 => S, 2 => V + * + */ + public function rgb2hsv($rgb) + { + // RGB values = 0 ÷ 255 + $var_R = ($rgb[0] / 255); + $var_G = ($rgb[1] / 255); + $var_B = ($rgb[2] / 255); + + // Min. value of RGB + $var_Min = min($var_R, $var_G, $var_B); + + // Max. value of RGB + $var_Max = max($var_R, $var_G, $var_B); + + // Delta RGB value + $del_Max = $var_Max - $var_Min; + + $V = $var_Max; + + // This is a gray, no chroma... + if ( $del_Max == 0 ) { + // HSV results = 0 ÷ 1 + $H = 0; + $S = 0; + } else { + // Chromatic data... + $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 += 1; + } + if ($H > 1) { + $H -= 1; + } + } + + // Returns agnostic values. + // Range will depend on the application: e.g. $H*360, $S*100, $V*100. + return array($H, $S, $V); + } + + /** + * + * Converts RGB to HSL. + * + * @param array $rgb RGB values: 0 => R, 1 => G, 2 => B + * + * @return array HSL values: 0 => H, 1 => S, 2 => L + * + */ + public function rgb2hsl($rgb) + { + // Where RGB values = 0 ÷ 255. + $var_R = $rgb[0] / 255; + $var_G = $rgb[1] / 255; + $var_B = $rgb[2] / 255; + + // Min. value of RGB + $var_Min = min($var_R, $var_G, $var_B); + // Max. value of RGB + $var_Max = max($var_R, $var_G, $var_B); + // Delta RGB value + $del_Max = $var_Max - $var_Min; + + $L = ($var_Max + $var_Min) / 2; + + if ( $del_Max == 0 ) { + // This is a gray, no chroma... + // HSL results = 0 ÷ 1 + $H = 0; + $S = 0; + } else { + // Chromatic data... + if ($L < 0.5) { + $S = $del_Max / ($var_Max + $var_Min); + } else { + $S = $del_Max / ( 2 - $var_Max - $var_Min ); + } + + $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 += 1; + } + if ($H > 1) { + $H -= 1; + } + } + + return array($H, $S, $L); + } + + /** + * + * Converts HSV colors to hexadecimal. + * + * @param array $hsv HSV values: 0 => H, 1 => S, 2 => V + * + * @return string Hexadecimal value with six digits, e.g., CCCCCC. + * + */ + public function hsv2hex($hsv) + { + return $this->rgb2hex($this->hsv2rgb($hsv)); + } + + /** + * + * Converts HSV to RGB. + * + * @param array $hsv HSV values: 0 => H, 1 => S, 2 => V + * + * @return array RGB values: 0 => R, 1 => G, 2 => B + * + */ + public function hsv2rgb($hsv) + { + $H = $hsv[0]; + $S = $hsv[1]; + $V = $hsv[2]; + + // HSV values = 0 ÷ 1 + if ($S == 0) { + $R = $V * 255; + $G = $V * 255; + $B = $V * 255; + } else { + $var_h = $H * 6; + // H must be < 1 + if ( $var_h == 6 ) { + $var_h = 0; + } + // Or ... $var_i = floor( $var_h ) + $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 ) ) ); + + switch($var_i) { + case 0: + $var_r = $V; + $var_g = $var_3; + $var_b = $var_1; + break; + case 1: + $var_r = $var_2; + $var_g = $V; + $var_b = $var_1; + break; + case 2: + $var_r = $var_1; + $var_g = $V; + $var_b = $var_3; + break; + case 3: + $var_r = $var_1; + $var_g = $var_2; + $var_b = $V; + break; + case 4: + $var_r = $var_3; + $var_g = $var_1; + $var_b = $V; + break; + default: + $var_r = $V; + $var_g = $var_1; + $var_b = $var_2; + } + + //RGB results = 0 ÷ 255 + $R = $var_r * 255; + $G = $var_g * 255; + $B = $var_b * 255; + } + + return array($R, $G, $B); + } + + /** + * + * Converts HSV colors to HSL. + * + * @param array $hsv HSV values: 0 => H, 1 => S, 2 => V + * + * @return array HSL values: 0 => H, 1 => S, 2 => L + * + */ + public function hsv2hsl($hsv) + { + return $this->rgb2hsl($this->hsv2rgb($hsv)); + } + + /** + * + * Converts hexadecimal colors to HSL. + * + * @param array $hsl HSL values: 0 => H, 1 => S, 2 => L + * + * @return string Hexadecimal value. Accepts values with 3 or 6 numbers, + * with or without #, e.g., CCC, #CCC, CCCCCC or #CCCCCC. + * + */ + public function hsl2hex($hsl) + { + return $this->rgb2hex($this->hsl2rgb($hsl)); + } + + /** + * + * Converts HSL to RGB. + * + * @param array $hsv HSL values: 0 => H, 1 => S, 2 => L + * + * @return array RGB values: 0 => R, 1 => G, 2 => B + * + */ + public function hsl2rgb($hsl) + { + list($H, $S, $L) = $hsl; + + if ($S == 0) { + // HSL values = 0 ÷ 1 + // RGB results = 0 ÷ 255 + $R = $L * 255; + $G = $L * 255; + $B = $L * 255; + } else { + if ($L < 0.5) { + $var_2 = $L * (1 + $S); + } else { + $var_2 = ($L + $S) - ($S * $L); + } + + $var_1 = 2 * $L - $var_2; + + $R = 255 * $this->_hue2rgb($var_1, $var_2, $H + (1 / 3)); + $G = 255 * $this->_hue2rgb($var_1, $var_2, $H); + $B = 255 * $this->_hue2rgb($var_1, $var_2, $H - (1 / 3)); + } + + return array($R, $G, $B); + } + + /** + * + * Support method for hsl2rgb(): converts hue ro RGB. + * + * @param + * + * @param + * + * @param + * + * @return int + * + */ + protected function _hue2rgb($v1, $v2, $vH) + { + if ($vH < 0) { + $vH += 1; + } + + if ($vH > 1) { + $vH -= 1; + } + + if ((6 * $vH) < 1) { + return ($v1 + ($v2 - $v1) * 6 * $vH); + } + + if ((2 * $vH) < 1) { + return $v2; + } + + if ((3 * $vH) < 2) { + return ($v1 + ($v2 - $v1) * (( 2 / 3) - $vH) * 6); + } + + return $v1; + } + + /** + * + * Converts hexadecimal colors to HSL. + * + * @param array $hsl HSL values: 0 => H, 1 => S, 2 => L + * + * @return array HSV values: 0 => H, 1 => S, 2 => V + * + */ + public function hsl2hsv($hsl) + { + return $this->rgb2hsv($this->hsl2rgb($hsl)); + } + + /** + * + * Updates HSV values. + * + * @param array $hsv HSV values: 0 => H, 1 => S, 2 => V + * + * @param array $values Values to update: 0 => value to add to H (0 to 360), + * 1 and 2 => values to multiply S and V (0 to 100). Example: + * + * {{{code:php + * // Update saturation to 80% in the provided HSV. + * $hsv = array(120, 0.75, 0.75); + * $new_hsv = $color->updateHsv($hsv, array(null, 80, null)); + * }}} + * + */ + public function updateHsv($hsv, $values) + { + if (isset($values[0])) { + $hsv[0] = max(0, min(360, ($hsv[0] + $values[0]))); + } + + if (isset($values[1])) { + $hsv[1] = max(0, min(1, ($hsv[1] * ($values[1] / 100)))); + } + + if (isset($values[2])) { + $hsv[2] = max(0, min(1, ($hsv[2] * ($values[2] / 100)))); + } + + return $hsv; + } + + /** + * + * Updates HSL values. + * + * @param array $hsl HSL values: 0 => H, 1 => S, 2 => L + * + * @param array $values Values to update: 0 => value to add to H (0 to 360), + * 1 and 2 => values to multiply S and V (0 to 100). Example: + * + * {{{code:php + * // Update saturation to 80% in the provided HSL. + * $hsl = array(120, 0.75, 0.75); + * $new_hsl = $color->updateHsl($hsl, array(null, 80, null)); + * }}} + * + */ + public function updateHsl($hsl, $values) + { + if (isset($values[0])) { + $hsl[0] = max(0, min(360, ($hsl[0] + $values[0]))); + } + + if (isset($values[1])) { + $hsl[1] = max(0, min(1, ($hsl[1] * ($values[1] / 100)))); + } + + if (isset($values[2])) { + $hsl[2] = max(0, min(1, ($hsl[2] * ($values[2] / 100)))); + } + + return $hsl; + } +} --- /dev/null +++ b/lib/bubbletree