switched to an options array

This commit is contained in:
Joshua Seigler 2016-06-28 00:05:26 -04:00
parent 9e83c583d8
commit 1ed50094fd
3 changed files with 64 additions and 39 deletions

View file

@ -2,7 +2,17 @@
class SVGChartBuilder { class SVGChartBuilder {
public static function renderStockChart($chartData, $width = 700, $lineColor = "#FF2F00", $gridLabelColor = "#999", $smoothed = false) { public static function renderStockChart($chartData, $options) {
function arrayGet($array, $key, $default = NULL)
{
return isset($array[$key]) ? $array[$key] : $default;
}
$width = arrayGet($options, "width", 800) - 100;
$height = arrayGet($options, "height");
$lineColor = arrayGet($options, "lineColor", "#FF2F00");
$labelColor = arrayGet($options, "labelColor", "#999");
$smoothed = arrayGet($options, "smoothed", false);
// we assume $chartData is sorted by key and keys and values are all numeric // we assume $chartData is sorted by key and keys and values are all numeric
$previousY = $previousY = null; $previousY = $previousY = null;
end($chartData); end($chartData);
@ -40,33 +50,35 @@ class SVGChartBuilder {
$yRange = $yMax - $yMin; $yRange = $yMax - $yMin;
$averageAbsSlope /= $yRange * $deltaX; // turn this absolute-deltas total into a slope $averageAbsSlope /= $yRange * $deltaX; // turn this absolute-deltas total into a slope
// take all these slopes and average them with their neighbors if ($smoothed) {
// unless they change direction, then make them zero // take all these slopes and average them with their neighbors
// also restrict them a bit when they are very different // unless they change direction, then make them zero
$previousSecant = $previousX = null; // also restrict them a bit when they are very different
foreach ($secants as $x => $secant) { $previousSecant = $previousX = null;
if (!is_null($previousSecant)) { foreach ($secants as $x => $secant) {
$tangents[$x] = ($secant + $previousSecant) / 2; if (!is_null($previousSecant)) {
if ($secant == 0 || $previousSecant == 0 || $secant * $previousSecant <= 0) $tangents[$x] = ($secant + $previousSecant) / 2;
{ if ($secant == 0 || $previousSecant == 0 || $secant * $previousSecant <= 0)
$tangents[$x] = 0; {
} else { $tangents[$x] = 0;
if ($tangents[$x] / $previousSecant > 3) { } else {
$tangents[$x] = 3 * $previousSecant; if ($tangents[$x] / $previousSecant > 3) {
} else if ($tangents[$x] / $secant > 3) { $tangents[$x] = 3 * $previousSecant;
$tangents[$x] = 3 * $secant; } else if ($tangents[$x] / $secant > 3) {
$tangents[$x] = 3 * $secant;
}
} }
} }
} if ($x == $xMax) {
if ($x == $xMax) { $tangents[$x] = $secant;
$tangents[$x] = $secant; }
} if ($x == $xMin) {
if ($x == $xMin) { $tangents[$x] = $secant;
$tangents[$x] = $secant; }
}
$previousX = $x; $previousX = $x;
$previousSecant = $secant; $previousSecant = $secant;
}
} }
/* /*
@ -114,18 +126,20 @@ class SVGChartBuilder {
transformX($x, $xMin, $xRange, $width).",". transformX($x, $xMin, $xRange, $width).",".
transformY($y, $yMax, $yRange, $height) . "\n"; transformY($y, $yMax, $yRange, $height) . "\n";
$controlX = $deltaX / 3 / sqrt(1 + $tangents[$x]**2); if ($smoothed) {
$controlY = $tangents[$x] * $controlX; $controlX = $deltaX / 3 / sqrt(1 + $tangents[$x]**2);
if ($x != $xMin) { $controlY = $tangents[$x] * $controlX;
$chartSplines .= " S". if ($x != $xMin) {
transformX($x - $controlX, $xMin, $xRange, $width).",". $chartSplines .= " S".
transformY($y - $controlY, $yMax, $yRange, $height)." ". transformX($x - $controlX, $xMin, $xRange, $width).",".
transformX($x, $xMin, $xRange, $width).",". transformY($y - $controlY, $yMax, $yRange, $height)." ".
transformY($y, $yMax, $yRange, $height); transformX($x, $xMin, $xRange, $width).",".
transformY($y, $yMax, $yRange, $height);
}
} }
} }
$numLabels = 1 + ceil($height / 60); $numLabels = 2 + ceil($height / 60);
$labelInterval = $yRange / $numLabels; $labelInterval = $yRange / $numLabels;
$labelModulation = 10 ** (1 + floor(-log($yRange / $numLabels, 10))); $labelModulation = 10 ** (1 + floor(-log($yRange / $numLabels, 10)));
@ -192,7 +206,7 @@ class SVGChartBuilder {
.chart__gridLines { .chart__gridLines {
font-family: sans-serif; font-family: sans-serif;
font-size: 10; font-size: 10;
fill: '.( $gridLabelColor ).'; fill: '.( $labelColor ).';
text-anchor: end; text-anchor: end;
shape-rendering: crispEdges; shape-rendering: crispEdges;
} }

View file

@ -20,7 +20,7 @@ spl_autoload_register(function ($class_name) {
$chartData = []; $chartData = [];
$offset = 100 * (rand()/getRandMax())**4; $offset = 100 * (rand()/getRandMax())**4;
$scale = 100 * (rand()/getRandMax())**4; $scale = 100 * (rand()/getRandMax())**2;
$volatility = 0.5 * (rand()/getRandMax())**3; $volatility = 0.5 * (rand()/getRandMax())**3;
for ($n = 0, $current = $offset + 0.5 * $scale; $n < 96; $n++) { for ($n = 0, $current = $offset + 0.5 * $scale; $n < 96; $n++) {
@ -30,4 +30,10 @@ for ($n = 0, $current = $offset + 0.5 * $scale; $n < 96; $n++) {
$chartData[$n] = $current; $chartData[$n] = $current;
} }
print SVGChartBuilder::renderStockChart($chartData, 1000, "#708", "#777", false); print SVGChartBuilder::renderStockChart($chartData, [
'width'=>1000,
'height'=>250,
'lineColor'=>"#708",
'labelColor'=>"#777",
'smoothed'=>false
]);

View file

@ -20,7 +20,7 @@ spl_autoload_register(function ($class_name) {
$chartData = []; $chartData = [];
$start = 100 * (rand()/getRandMax())**3; $start = 100 * (rand()/getRandMax())**3;
$volatility = rand()/getRandMax(); $volatility = rand()/getRandMax() + 0.01;
$velocity = (rand()/getRandMax() - 0.5); $velocity = (rand()/getRandMax() - 0.5);
$acceleration = 0.1 * (rand()/getRandMax())**2; $acceleration = 0.1 * (rand()/getRandMax())**2;
@ -31,4 +31,9 @@ for ($n = 0, $current = $start; $n < 24; $n++) {
$chartData[$n] = $current; $chartData[$n] = $current;
} }
print SVGChartBuilder::renderStockChart($chartData, 1000, "#708", "#777", true); print SVGChartBuilder::renderStockChart($chartData, [
'width'=>1000,
'lineColor'=>"#708",
'labelColor'=>"#777",
'smoothed'=>true
]);