'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" . '\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 = '