diff --git a/Util.php b/Util.php index 798dfdd..53ab1cf 100644 --- a/Util.php +++ b/Util.php @@ -35,4 +35,6 @@ class Util { } return $median; } + } + diff --git a/buffer.php b/buffer.php index 9297b20..d5a2637 100644 --- a/buffer.php +++ b/buffer.php @@ -3,6 +3,8 @@ // Based on PHP code by Dennis Pallett: www.phpit.net // Please acknowledge use of this code by including this header. + // Updated to include and use last-modified and etag headers + // location and prefix for cache files define('CACHE_PATH', "/tmp/cache_"); @@ -22,7 +24,20 @@ // check that cache file exists and is not too old if(!file_exists($file)) return; - if(filemtime($file) < time() - CACHE_TIME) return; + $last_modified_time = filemtime($file); + if($last_modified_time < time() - CACHE_TIME) return; + $etag = md5_file($file); + + // always send headers + header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT"); + header("Etag: $etag"); + + // exit if not modified + if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time || + @trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { + header("HTTP/1.1 304 Not Modified"); + exit; + } // if so, display cache file and stop processing readfile($file); @@ -36,6 +51,13 @@ fwrite($f, $content); fclose($f); } + $last_modified_time = filemtime($file); + $etag = md5_file($file); + + // always send headers + header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT"); + header("Etag: $etag"); + return $content; } diff --git a/cms_chart.php b/cms_chart.php deleted file mode 100644 index 1305fff..0000000 --- a/cms_chart.php +++ /dev/null @@ -1,676 +0,0 @@ - '1.2.3.4') exit; - //if ($_SERVER['HTTP_REFERER'] <> 'topnew.net') exit; // etc - cms_chart($_GET['data'], $init); -} -**** disabled for security reasons - */ - -/** - * Topnew CMS Chart v5.5.5 - Released on 2016.05.05 - * The MIT License (MIT) Copyright (c) 1998-2015, Topnew Geo, topnew.net/chart - * Draw an SVG chart (bar, barV, barS, line or pie), responsive to parent box - * - * Method 2 - include this file and call cms_chart() in your php file - * - * @param array $data = array() or string -- check cms_chart_data() for details - * @param array $init = array() as following: - * chart = bar [default], line, pie, barV, barS - * w = px of SVG width default 480px. Tip: bigger w will produce fine charts - * w = fix : will auto set w according to number of bar/line - * h = px of SVG height default 250px. Pie chart will auto set h according to w - * gapT, gapR, gapB, gapL = px of gaps on Top, Right, Bottom and Left - * title = title of the chart - * xTitle = title on axisX - * yTitle = title on axisY - * titleAlign, xTitleAlign, yTitleAlign = 1 Left 2 Center [default] 3 Right - * xSkip = 5 means skip 5 labels between each two - * xSkipMax = 50 means skip floor(xNum / 50) - * xSkip = -5 when negative it means substr(xKey,-2) % -5 is true eg 5 10 15 ... - * legend = T(op), R(ight) [default], B(ottom), 0 none - * legendW = px of legend width - * yUnit = additional text after axisY label - * xFormat, yFormat = php . substr|fm|to or format|decimal|,|. or date|M - * xKey = year, month, week, day, hour - * xMin, xMax default to data min and max - * sort = y (sort on axisY labels, or yVal for only one serial chart) - * sort = x (sort on axisX labels), '' default none - * color = fffccc,cccfff : add 2 color at front - * colorAdd = fffccc,cccfff : add 2 color at end - * colorDel = 0,2 : delete color #0 and #2 - * ySum = 1 : sum up yVal while x moves, default 0 - * xSum = 8 (substr(xAxis,0,8)) or 5,2 or -2 to call php::substr - * pieArc = 0 ~ 360 for pie : start Arc - * pieStripe = 0 / 1 for pie - * piePct = 0 / 1 for pie to include % - * pieDonut = 0 / 1 pie or donut - * css = 0 / 1 to cout default chart css style - * style = '...' : to include customized css style to over-write default css - * fmt = '' sxy xsy sxx xss, str str_***, sql sql_*** please check chart_data() - * sepCol = , : data seperator to cut columns for str_*** data - * sepRow = ; : data seperator to cut rows for str_*** data - * valShow = 0 / 1 : show value - * valAngle = -90 ~ 90 - * xAngle = -90 ~ 90 - * - * TODO: barV with negative values, it is confusing and not displaying correctly - * legendW looks like buggy - * &init looks horrible -- need redesign - * also negative value for pie is ignored - * other para tobe added = font fontSize yAxis=2 - */ -function cms_chart(&$data = null, $init = null) { - $ceil = array('w', 'h', 'gapT', 'gapR', 'gapB', 'gapL', 'legendW', 'titleAlign', 'xTitleAlign', 'yTitleAlign', 'xSkip', 'xSkipMax', 'xAngle', 'ySum', 'pieArc', 'pieStripe', 'piePct', 'pieDonut', 'css', 'valAngle', 'valShow'); - $trim = array('chart', 'fmt', 'title', 'legend', 'style', 'sepCol', 'sepRow', 'xTitle', 'yTitle', 'yUnit', 'xFormat', 'yFormat', 'xMin', 'xMax', 'xKey', 'sort', 'xSum'); - foreach ($ceil as $k) $arr[$k] = isset($init[$k]) ? ceil($init[$k]) : 0; - foreach ($trim as $k) $arr[$k] = isset($init[$k]) ? trim($init[$k]) : ''; - $data = cms_chart_data($data, $arr['fmt'], $arr['sort'], $arr['xKey'], $arr['xMin'], $arr['xMax'], $arr['sepRow'], $arr['sepCol'], $arr['ySum'], 'barS' === $arr['chart']); - if (!$data) return; - $color = cms_chart_color($init); - $init = cms_chart_init($arr, $data, 'fix' === (isset($init['w']) ? $init['w'] : '')); - extract($init); - $init['color'] = $color; - echo "\n" . ''; - cms_chart_css($css, $style); - echo "\n" . ' '; - echo "\n" . ' '; - $is_pie = ('pie' === $chart); - if (!$is_pie) { - $is_bar = ('bar' === substr($chart, 0, 3)); - $is_barV = ('barV' === $chart); - cms_chart_axisX($data, $x1, $y1, $x2, $y2, $xVal, $xSkip, $xFormat, $is_bar, $xAngle, $yUnit, $yFormat, $color, $mouseInfo); - cms_chart_axisY($data, $x1, $y1, $x2, $y2, $yVal, $yUnit, $yFormat, $is_barV); - $zoom = $y2 / abs($yVal[0] - end($yVal)); - $init['xVal'] = $xVal; - $init['yVal'] = $yVal; - } - cms_chart_title($y1, $y2, $w, $title, $titleAlign, $xTitle, $xTitleAlign, $yTitle, $yTitleAlign, $is_pie); - if ($is_pie) { - $data = reset($data); - foreach ($data as $k => $v) { - if ($v < 0 || !$v) unset($data[$k]); - } - } - cms_chart_legend($data, $color, $legend, $legendW, $x1, $y1, $x2, $y2, $xTitle, $is_pie, $piePct); - echo "\n \n" . ' '; - if ('line' == $chart) cms_chart_line($data, $color, $zoom, $xVal, $yVal[0], $valShow, $valAngle, $yFormat); - elseif ('pie' == $chart) cms_chart_pie($data, $color, round($y2 / 2, 5), $pieArc, $pieStripe, $piePct, $pieDonut, $valShow, $yFormat); - else cms_chart_bar($data, $color, $zoom, $xVal, $yVal[0], $is_barV, 'barS' === $chart, $valShow, $valAngle, $yFormat); - echo "\n "; - if (!$is_pie) echo $mouseInfo; - echo "\n\n"; -} -/** - * --------------------------------------------------------------------------- - * data fmt = '' || sxy, xsy, xss, sxx (all as array) - * --------------------------------------------------------------------------- - * fmt = '' or sxy (default) : col1 = serial, col2 = xAxis, col3 = yVal - * max 3 cols, col4+ will be ignored - * eg. select manager,month,count(*) qty from sales group by 1,2 - * Tom Jan 123 - * Sam May 234 - * data = cms_arr(sql,2) dirty or cms_arr(sql,2,1) clean - * - * fmt = xsy : col1 = xAxis, col2 = serial, col3 = yVal - * max 3 cols, col4+ will be ignored - * eg. select month,manager,count(*) qty from sales group by 1,2 - * Jan Tom 123 - * May Sam 234 - * data = cms_arr(sql,2) dirty or cms_arr(sql,2,1) clean - * -- as a result this data same as xss - * - * fmt = xss : col1 = xAxis, col2...x = serial, yVal in the grid - * eg. select month,count(*) qty,sum(amt) amt from sales group by 1 - * Jan 123 956 789 ... - * Feb 222 933 444 ... - * data = cms_arr(sql,1) -- only this need to convert to default sxy - * - * fmt = sxx : col1 = serial, col2...x = xAxis, yVal in the grid - * very rarely when the col name is xAxis - * eg. select manager,jan,feb,march from rep_sales - * Tom 123 456 789 ... - * Sam 222 333 444 ... - * data = cms_arr(sql,1) -- data same as default sxy - * - * when there is only 2 cols, which means only 1 serial - * no matter which fmt : col1 = xAxis, col2 = yVal - * eg. select month,count(*) qty from sales group by 1 - * Jan 123 - * Feb 234 - * data = cms_row(sql,2) = cms_arr(sql,1,1) or dirty cms_arr(sql,1) - * --------------------------------------------------------------------------- - * as a result, if you can not remember which func to get data, remember this: - * data = cms_arr(sql,2) : when fmt got 3 different chars eg xsy sxy - * data = cms_arr(sql,1) : when fmt only has 2 different chars eg xss sxx - * - * --------------------------------------------------------------------------- - * fmt = str || str_sxy, str_xsy, str_xss, str_sxx (all as string) - * --------------------------------------------------------------------------- - * default sepCol = , sepRow = ; - * - * str_sxy = 'Staff,month,Qty;Tom,Feb,12;Tom,Mar,34;Sam,Jan,112;...' - * str_xsy = 'month,Staff,Qty;Feb,Tom,12;Mar,Tom,34;Jan,Sam,112;...' - * str_xss = 'month,Qty,Vol;Feb,22,12;Mar,31,34;May,12,112;...' - * str_sxx = 'Staff,Jan,Feb,Mar;Tom,1,2,3;Sam,2,3,4;...' - * - * --------------------------------------------------------------------------- - * fmt = sql || sql_sxy, sql_xsy, sql_xss, sql_sxx (all as SQL) - * --------------------------------------------------------------------------- - * you need cms_arr() and cms_row() etc cms db function plugin to run this - * - * sql_sxy cms_arr(sql,2) select staff,year,count(*) from sales group by 1,2; - * sql_xsy cms_arr(sql,2) select year,staff,count(*) from sales group by 1,2; - * sql_xss cms_arr(sql,1) select year,count(*) qty,sum(amt) vol from sales group by 1; - * sql_sxx cms_arr(sql,1) select staff,jan,feb,mar from rep_sales; - * - * if you only have 2 cols in sql, you have to set fmt = sql_sxx or sql_xss!!! - * sql_*** cms_arr(sql,1) select a,b from tab -- only 2 cols - */ -function cms_chart_data($data, $fmt, $sort, $xKey, $xMin, $xMax, $sepRow, $sepCol, $ySum, $is_barS) { - $fmt3 = substr($fmt, 0, 3); - if ('sql' === $fmt3) { - $fmt = substr($fmt, 4); - $data = cms_arr($data, ('sxx' === $fmt || 'xss' === $fmt ? 1 : 2)); - } elseif ('str' === $fmt3) { - $fmt = substr($fmt, 4); - $data = cms_chart_data_str($data, $fmt, $sepRow, $sepCol); - } elseif ('jso' === $fmt3) { - $data = json_decode($data, 1); - } - $num = count($data); - if (!$num) return; - if (!is_array(reset($data))) { - $data = array($data); // only 2 cols - $num = 1; - } elseif ('xss' === $fmt || 'xsy' === $fmt) { - foreach ($data as $x => $arr) { - foreach ($arr as $s => $y) $sxy[$s][$x] = $y; - } - $data = $sxy; - } - $keys = array(); // x labels - foreach ($data as $s => $arr) { - foreach ($arr as $x => $y) { - if (!in_array($x, $keys)) $keys[] = $x; - if (is_array($y)) $data[$s][$x] = reset($y); // clean dirty data - } - } - if (in_array($xKey, array('year','month','week','day','hour'))) { - $keys = cms_chart_data_ymdH($xKey, $keys, $xMin, $xMax); - } elseif ('x' === $sort) { - sort($keys); - } - if ('y' === $sort && $num > 1) ksort($data); - foreach ($data as $k => $arr) { - foreach ($keys as $k2) $res[$k][$k2] = isset($arr[$k2]) ? $arr[$k2] + 0 : 0; - } - if ('y' === $sort && 1 == $num) { // if pie make sure only 1 array - $pie = reset($res); - arsort($pie); - $res = array($pie); - } - if ($ySum) { - foreach ($res as $k => $arr) { - $j = $hold = 0; - foreach ($arr as $k2 => $v) { - if ($j++) $res[$k][$k2] += $hold; - $hold += $v; - } - } - } - if ($is_barS) { - foreach ($res as $k => $arr) $sortS[$k] = array_sum($arr); - array_multisort($sortS, SORT_DESC, $res); - } - return $res; -} -function cms_chart_data_str($str, $fmt, $sepRow, $sepCol) { - if (!$sepRow) $sepRow = ';'; - if (!$sepCol) $sepCol = ','; - $rows = explode($sepRow, trim($str)); - $head = explode($sepCol, trim(array_shift($rows))); - foreach ($head as $v) $cols[] = trim($v); - unset($cols[0]); - if (1 === count($cols)) { - foreach ($rows as $i => $r) { - $r = explode($sepCol, trim($r)); - $data[trim($r[0])] = trim($r[1]); - } - return $data; - } - foreach ($rows as $i => $r) { - $r = explode($sepCol, trim($r)); - foreach ($r as $j => $v) $r[$j] = trim($v); - if ('xss' === $fmt || 'sxx' === $fmt) { - foreach ($r as $j => $v) { - if ($j) $data[$r[0]][$cols[$j]] = $v; - } - } else { - $data[$r[0]][$r[1]] = isset($r[2]) ? $r[2] : 0; - } - } - return $data; -} -function cms_chart_data_ymdH($xKey, $keys, $xMin, $xMax) { - if (!$xMin) $xMin = min($keys); - if (!$xMax) $xMax = max($keys); - $y1 = substr($xMin, 0, 4); $y2 = substr($xMax, 0, 4); - if ('year' === $xKey) return range($y1, $y2); - $keys = array(); - if ('week' === $xKey) { - $xMin = substr($xMin, 0, 6); $xMax = substr($xMax, 0, 6); - for ($Y = $y1; $Y <= $y2; $Y++) { for ($W = 1; $W < 54; $W++) { - $yw = $Y . str_pad($W, 2, 0, STR_PAD_LEFT); - if ($yw >= $xMin && $yw <= $xMax) $keys[] = $yw; - }} // year week - return $keys; - } - $m1 = substr($xMin, 0, 7); $d1 = substr($xMin, 0, 10); - $m2 = substr($xMax, 0, 7); $d2 = substr($xMax, 0, 10); - for ($Y = $y1; $Y <= $y2; $Y++) { for ($M = 1; $M < 13; $M++) { - $ym = $Y .'-'. str_pad($M, 2, 0, STR_PAD_LEFT); - if ($ym >= $m1 && $ym <= $m2) { - if ('month' === $xKey) $keys[] = $ym; - else { for ($D = 1; $D < 32; $D++) { - $ymd = $ym .'-'. str_pad($D, 2, 0, STR_PAD_LEFT); - if (checkdate($M, $D, $Y) && $ymd >= $d1 && $ymd <= $d2) { - if ('day' === $xKey) $keys[] = $ymd; - else { for ($H = 0; $H < 24; $H++) { - $keys[] = $ymd .' '. str_pad($H, 2, 0, STR_PAD_LEFT); - }} // hour - } // valid day - }} // day - } // valid m - }} // y m - return $keys; -} -function cms_chart_init($arr, $data, $wFix = 0) { - $num = count($data); - $xNum = count(reset($data)); - if (!$arr['xSkip'] && $arr['xSkipMax'] > 0) $arr['xSkip'] = floor($xNum / $arr['xSkipMax']); - if (!$arr['chart'] || !in_array($arr['chart'], array('line','pie','barV','barS'))) $arr['chart'] = 'bar'; - $is_pie = ('pie' === $arr['chart']); - $arr['gapL'] += 9; // default box margin 9px each side - $arr['gapT'] += 9; - $arr['gapR'] += 9; - $arr['gapB'] += 9; - if ($arr['title']) $arr['gapT'] += 15; - if ($arr['xTitle']) $arr['gapB'] += 15; - if ($arr['yTitle']) $arr['gapL'] += 15; - if (!strlen($arr['legend'])) $arr['legend'] = ($num > 1 || $is_pie) ? 'R' : '0'; - if ($arr['legendW'] < 1) $arr['legendW'] = 80; - if ($arr['legend']) { // 0 T B R - if ('T' === $arr['legend']) $arr['gapT'] += 15; - elseif ('B' === $arr['legend']) $arr['gapB'] += 15; - elseif ('L' === $arr['legend']) $arr['gapL'] += $arr['legendW']; - else $arr['gapR'] += $arr['legendW']; - } - if ($is_pie) { - if ($arr['yTitle']) $arr['gapL'] += 3; - if ('L' === $arr['legend']) $arr['gapL'] += 51; - elseif ('R' === $arr['legend']) $arr['gapR'] += 51; - } else { - $arr['gapL'] += 51; // default yLabel - $arr['gapB'] += 16; // default xLabel - } - $arr['x1'] = $arr['gapL']; - $arr['y1'] = $arr['gapT']; - if ($arr['x1'] < 0) $arr['x1'] = 0; - if ($arr['y1'] < 0) $arr['y1'] = 0; - - if (!$is_pie && $wFix) { - $arr['x2'] = 10 * $num * $xNum + $xNum + 1; - $arr['w'] = $arr['x1'] + $arr['x2'] + $arr['gapR']; - } else { - if ($arr['w'] < 1) $arr['w'] = 480; - $arr['x2'] = $arr['w'] - $arr['x1'] - $arr['gapR']; - if ($arr['x2'] > $arr['w'] || $arr['x2'] < $arr['x1']) $arr['x2'] = $arr['w']; - } - if ($arr['h'] < 1) $arr['h'] = 250; - if ($arr['h'] > $arr['w']) $arr['h'] = $arr['w']; - if ($is_pie) { - $arr['y2'] = $arr['x2']; - $arr['h'] = $arr['y1'] + $arr['y2'] + $arr['gapB']; // pie h auto calculated - } else { - $arr['y2'] = $arr['h'] - $arr['y1'] - $arr['gapB']; - if ($arr['y2'] > $arr['h'] || $arr['y2'] < $arr['y1']) $arr['y2'] = $arr['h']; - } - return $arr; -} -function cms_chart_color($init) { - // the following are default 11 colors - $defa = array('d9534f', 'f0ad4e', '5bc0de', '5cb85c', '337ab7', 'f26522', '754c24', 'd9ce00', '0e2e42', 'ce1797','672d8b'); - // add colors at front - if (isset($init['color']) && !is_array($init['color'])) { - $col = explode(',', $init['color']); - if (is_array($col)) { - foreach ($col as $c) { - $c = trim(substr(trim($c), 0, 6)); - if (strlen($c) > 2) $color[] = $c; - } - } - } - // del colors - if (isset($init['colorDel'])) { - $col = explode(',', $init['colorDel']); - if (is_array($col)) { - foreach ($col as $c) { - unset($defa[ceil($c)]); - } - } - } - foreach ($defa as $c) $color[] = $c; - // add colors at end - if (isset($init['colorAdd'])) { - $col = explode(',', $init['colorAdd']); - if (is_array($col)) { - foreach ($col as $c) { - $c = trim(substr(trim($c), 0, 6)); - if (strlen($c) > 2) $color[] = $c; - } - } - } - return $color; -} -function cms_chart_axisX($data, $x1, $y1, $x2, $y2, &$xVal, $xSkip, $xFormat, $is_bar, $xAngle, $yUnit, $yFormat, $color, &$mouseInfo) { - $xNum = count(reset($data)); - if ($is_bar) { - $xDiv = ($x2 - $xNum - 1) / $xNum; - $xVal[0] = round($xDiv / 2 + 1, 5); - $xDiv++; - $xLeft = 0; - } else { - $xDiv = $x2 / ($xNum - 1); - $xVal[0] = 0; - $xLeft = $xDiv / 2; - } - $xLabel = array_keys(reset($data)); - if ($xAngle) { - $angle1 = '';// best for 45 - $angle2 = ''; - $angleCSS = ' xAngle'; - } else { - $angle1 = $angle2 = $angleCSS = ''; - } - echo "\n" . ' '; - if ($yUnit) $yUnit = ' ' . $yUnit; - $cNum = count($color); - $j = 0; - foreach ($data as $k => $arr) { - $i = 0; - foreach ($arr as $k2 => $v) { - if ($i) $xVal[$i] = round($xVal[$i - 1] + $xDiv, 5); - if (!isset($labelTxt[$i])) $labelTxt[$i] = ''. $k2 .''; - $labelTxt[$i] .= ''. ($k ? $k .' : ' : '') . cms_chart_axis_format($v, $yFormat) . $yUnit .''; - $i++; - } - $j++; - } - $mouseInfo = "\n" .' '; - $mouseInfoH= (count($data) + 1) * 15 + 7; - for ($i = 0, $skip = 0; $i < $xNum; $i++) { - $rect = ''. $rect .'height="'. $y2 .'" fill="#000" opacity="0"/>'. $rect .'height="'. $mouseInfoH .'"/>'. $labelTxt[$i] .''; - if (!$xSkip || ($xSkip > 0 && $i == ($xSkip + 1) * $skip) - || ($xSkip < 0 && !(substr($xLabel[$i], -2) % $xSkip))) { - $skip++; - echo "\n" . ' '; - echo $angle1 . ''. cms_chart_axis_format($xLabel[$i], $xFormat) .'' . $angle2; - echo ''; - } - } - $mouseInfo .= "\n "; - echo "\n" . ' '; -} -function cms_chart_axisY($data, $x1, $y1, $x2, $y2, &$yVal, $yUnit, $yFormat, $is_barV) { - $max_min = reset($data); - $max = $min = reset($max_min); - if ($is_barV) { - foreach ($data as $arr) { - foreach ($arr as $k => $v) $TTL[0][$k] = $v + (isset($TTL[0][$k]) ? $TTL[0][$k] : 0); - } - } else $TTL = $data; - foreach ($TTL as $arr) { - $min = min(min($arr), $min); - $max = max(max($arr), $max); - } - if ($max < 0 && $min < 0) $ttl = $min; - elseif ($max < 0 || $min < 0) $ttl = $max - $min; - else $ttl = $max; - if ($ttl < 0) $ttl = abs($ttl); - $zoom = pow(10, floor(log10($ttl))); - $ttl /= $zoom; - if ($ttl == 1) $step = 0.2; - elseif ($ttl > 6) $step = 2; - elseif ($ttl > 5) $step = 1.2; - elseif ($ttl > 4) $step = 1; - elseif ($ttl > 3) $step = 0.8; - elseif ($ttl > 2) $step = 0.6; - else $step = 0.4; - if ($max <= 0 && $min < 0) { - for ($i = 0; $i < 6; $i++) $yVal[] = 0 - $i * $zoom * $step; - } else { - for ($i = 5; $i >- 1; $i--) $yVal[] = $i * $zoom * $step; - if ($max <= 0 || $min < 0) cms_chart_axisY_audit($max, $min, $step, $zoom, $yVal); - } - if ($max > 0 && $yVal[1] >= $max) array_shift($yVal); - elseif ($min < 0 && $yVal[4] <= $min) array_pop($yVal); - $step = count($yVal); - if ($min < $yVal[$step-1]) $yVal[] = $yVal[$step-1] - abs($yVal[$step-2] - $yVal[$step-3]); - $step = $y2 / (count($yVal) - 1); - - echo "\n" . ' '; - $yDiv = count($yVal); - $last_not_zero = end($yVal); - if ($yUnit) $yUnit = ' ' . $yUnit; - for ($i = 0; $i < $yDiv; $i++) { - echo "\n" . ' '; - if ($yVal[$i] || $last_not_zero) { - echo ''. cms_chart_axis_format($yVal[$i], $yFormat) . $yUnit . ''; - } - echo ''; - } - echo "\n" . ' '; -} -function cms_chart_axisY_audit($max, $min, $step, $zoom, &$yVal, $count = 0) { - if ($count > 5) return; - if ($yVal[1] > $max && $yVal[5] > $min) { - $yVal[] = $yVal[5] - $zoom * $step; - array_shift($yVal); - cms_chart_axisY_audit($max, $min, $step, $zoom, $yVal, $count++); - } -} -function cms_chart_axis_format($v, $format) { - if (!$format) return $v; - $format = explode('|', $format, 4); // eg substr|6 or format|0|.|, or data|M - if ('format' == $format[0]) return number_format($v, isset($format[1]) ? ceil($format[1]) : 0, isset($format[2]) ? $format[2] : null, isset($format[3]) ? $format[3] : null); - if ('substr' == $format[0]){ - if (isset($format[2])) return substr($v, ceil($format[1]), ceil($format[2])); - return substr($v, isset($format[1]) ? ceil($format[1]) : 0); - } - if ('date' == $format[0]) return date($format[1], strtotime($v)); - return $v; -} -function cms_chart_title($y1, $y2, $w, $title, $titleAlign, $xTitle, $xTitleAlign, $yTitle, $yTitleAlign, $is_pie) { - if ($title) { - echo "\n" . ' '. $title .''; - } - $y = $y1 + $y2; - if ($xTitle) { - echo "\n".' '. $xTitle .''; - } - if ($yTitle) { - echo "\n".' '. $yTitle .''; - } -} -function cms_chart_legend($data, $color, $legend, $legendW, $x1, $y1, $x2, $y2, $xTitle, $is_pie, $piePct) { - if (!$legend || (count($data) < 2 && !$is_pie)) return; - $i = 0; - if ('T' === $legend || 'B' === $legend) { - $x = $legendW; - $y = 0; - if ('B' === $legend) $y1 += $y2 + ($is_pie ? 25 : 40) + ($xTitle ? 15 : 0); - } else { - $x = 0; - $y = 16; - $y1 += 15; - if ('L' === $legend) $x1 = 9; - else $x1 += $x2 + 8; - } - echo "\n" . ' '; - $cNum = count($color); - foreach ($data as $k => $arr) { - echo "\n" . ' '; - $cx = $x1 + 6 + $i * $x; - $cy = $y1 - 10 + $i * $y; - echo ''. $k .''; - echo ''; - $i++; - } -} -function cms_chart_bar($data, $color, $zoom, $xVal, $yVal0, $is_barV, $is_barS, $valShow, $valAngle, $yFormat) { - $i = 0; - $w1 = $xDiv = abs((isset($xVal[1]) ? $xVal[1] : 0) - $xVal[0] - 1); - $half = $xDiv / 2; - if (!$is_barV && !$is_barS) $w1 /= count($data); - $w1 = round($w1, 5); - $cNum = count($color); - $is_barVS = $is_barV || $is_barS; - $opacity = $is_barS ? ' opacity=".8"' : ''; - if ($valShow) { - if (-90 == $valAngle) $xMove = 4; - elseif ($valAngle > 0) $xMove = -3; - else $xMove = 0; - $yMove = (45 == $valAngle) ? 5 : 0; - $valClass = ' class="valShow"'; - } else { - $valClass = ''; - } - foreach ($data as $arr) { - echo "\n" . ' '; - $j = 0; - foreach ($arr as $v) { - $hold[$i][$j] = $v; - if ($is_barV) { - // when more than 1 negative bar, barV does not work--fix later - if ($i) $Y[$j] = (isset($Y[$j]) ? $Y[$j] : 0) + ($hold[$i-1][$j] > 0 ? $hold[$i-1][$j] : 0); - } else $Y[$j] = 0; - //if ($is_barV && $i) $Y[$j] += $hold[$i-1][$j]; - //else $Y[$j] = 0; - $x = $xVal[$j] - $half + ($is_barVS ? 0 : $i * $w1); - $y = $yVal0 - (isset($Y[$j]) ? $Y[$j] : 0); - if ($v > 0) $y -= $v; - $x = round($x, 5); - $y = round($y * $zoom, 5); - echo "\n".' ';//remove inside rect: '. $v .' - if ($valShow && $v) echo cms_chart_val($valAngle, $x + $w1 /2, $y, $xMove, $yMove, cms_chart_axis_format($v, $yFormat)); - $j++; - } - echo "\n" . ' '; - $i++; - } -} -function cms_chart_val($valAngle, $x, $y, $xMove, $yMove, $v) { - if (!$valAngle) return ''. $v .''; - return "\n" .' '. $v .''; -} -function cms_chart_line($data, $color, $zoom, $xVal, $yVal0, $valShow, $valAngle, $yFormat) { - $i = 0; - $cNum = count($color); - foreach ($data as $arr) { - $j = 0; - $line = $dot = ''; - foreach ($arr as $v) { - $x = round($xVal[$j++], 5); - $y = round(($yVal0 - $v) * $zoom, 5); - $line .= ' '. $x .','. $y; - $dot .= "\n" . ' ';//removed: '. $v .' - if ($valShow) $dot .= cms_chart_val($valAngle, $x, $y - 15, 0, 0, cms_chart_axis_format($v, $yFormat)); - } - echo "\n" . ' '; - echo "\n" . ' '; -// echo $dot; - echo "\n" . ' '; - } -} -function cms_chart_pie($data, $color, $R, $Arc, $stripe, $piePct, $pieDonut, $valShow, $yFormat) { - $sum = array_sum($data); - foreach ($data as $k => $v) $pct[$k] = round($v / $sum, 5); - echo "\n" . ' '; - echo "\n" . ' '; - $i = 0; - $cNum = count($color); - foreach ($pct as $k => $v) { - $a = round($v * 360, 5); - if (360 == $a) echo "\n" . ' '; - elseif ($a) { - echo "\n" . ' '; - $r = deg2rad($a); - $x = round(cos($r) * $R, 5); - $y = round(sin($r) * $R, 5); - echo ' 180 ? 1 : 0) . ",1 $x,$y z\"/>"; - if ($valShow) echo ''. cms_chart_val(0, round($R * 3 / 4, 2), 0, 0, 0, cms_chart_axis_format($data[$k], $yFormat) . ($piePct ? ' ( '. round($v * 100) .' % )' : '')) .''; - echo ''; - $Arc += $a; - } - $i++; - } - if ($stripe) { - $stripeCSS = 'style="fill:none;stroke:#fff;stroke-width:'. round($R * 2 / 11, 5) .';opacity:0.2"'; - echo "\n \n " . ''; - echo "\n " . ''; - } - if ($pieDonut) echo "\n" . ' ';//donus - echo "\n" . ' '; -} -function cms_chart_css($css, $style) { - if (!$css && !$style) return; - echo '' . "\n"; -} diff --git a/dash/24h/index.php b/dash/24h/index.php deleted file mode 100644 index 3392181..0000000 --- a/dash/24h/index.php +++ /dev/null @@ -1,44 +0,0 @@ -date)] = $datum->weightedAverage; -} - -$chartConfig = array( - 'chart' => 'line', - 'css' => '1', - 'xKey' => 'Hour', - 'xFormat' => 'date|' . $dateformat, - 'xSkip' => '1', - 'yFormat' => 'format|6|.', - 'yKey' => 'BTC', -); - -Header('Content-type: image/svg+xml; charset=utf-8'); -print ' -'; -cms_chart($averages, $chartConfig); - diff --git a/index.html b/index.html deleted file mode 100644 index 91d2ed7..0000000 --- a/index.html +++ /dev/null @@ -1 +0,0 @@ -Under development diff --git a/index.php b/index.php new file mode 100644 index 0000000..926e43f --- /dev/null +++ b/index.php @@ -0,0 +1,170 @@ +date; + $thisY = $datum->weightedAverage; + $chartData[$thisX] = $thisY; + if (!is_null($previousValue)) { + $absoluteDeltas[] = abs($thisY - $previousValue); + } + if ($thisY < $yMin) { + $yMin = $thisY; + $yMinX = $thisX; + } + if ($thisY > $yMax) { + $yMax = $thisY; + $yMaxX = $thisX; + } + $previousValue = $thisY; +} +end($chartData); // already at end, not needed +$yRange = $yMax - $yMin; +$xMax = key($chartData); +reset($chartData); +$xMin = key($chartData); +$xRange = $xMax - $xMin; +$count = count($chartData); +$medianDelta = abs(Util::median($absoluteDeltas)); +$width = 700; + +/* +We want the height of the median y-delta to be the same as +the width of one x-delta, which puts the median slope at +45 degrees. This improves comprehension. +http://vis4.net/blog/posts/doing-the-line-charts-right/ +*/ +$aspectRatio = $yRange / $medianDelta / $count; +$height = floor($aspectRatio * $width); + +function labelFormat($float, $sigFigs = 4, $minPlaces = 1) { + return number_format($float, max( + $minPlaces, + $sigFigs + floor(-log($float, 10))) + /* this floor(log) thing is the first significant place value */ + ); +} + +/* Transform data coords to chart coords */ +function transformX($x) { + global $xMin, $xRange, $width; + return round( + ($x - $xMin) / $xRange * $width + , 2); +} +function transformY($y) { + global $yMax, $yRange, $height; + return round( + // SVG has y axis reversed, 0 is at the top + ($yMax - $y) / $yRange * $height + , 2); +} + +$chartPoints = "M"; +foreach ($chartData as $x => $y) { + $chartPoints .= transformX($x) . ',' . transformY($y) . ' + '; +} + +$numLabels = floor($height / 50); +$labelModulation = 2 * 10 ** (1 + floor(-log($yRange / $numLabels, 10))); +$labelInterval = round($yRange / $numLabels * $labelModulation) / $labelModulation; + +$gridLines = +"M0,0 ".$width.",0 +M0,".$height.",".$width.",".$height." +"; + +$gridText = + ''.labelFormat($yMax).'' . + ''.labelFormat($yMin).''; + +for ( + $labelY = $yMin + 0.5 * $labelInterval - fmod($yMin + 0.5 * $labelInterval , $labelInterval) + $labelInterval; + $labelY < $yMax - 0.5 * $labelInterval; + $labelY += $labelInterval +) { + + $labelHeight = transformY($labelY); + $gridLines .= "M0,".$labelHeight." ".$width.",".$labelHeight." + "; + $gridText .= ''.labelFormat($labelY).''; +} + +// in case some dingbat has PHP short tags enabled +echo '<'.'?xml version="1.0" standalone="no"?'.'>'; + +?> + + + + + + + + + + + + + + + + + + +