From 1ed50094fd062a81343a93d0519ca2c830a16af7 Mon Sep 17 00:00:00 2001 From: Joshua Seigler Date: Tue, 28 Jun 2016 00:05:26 -0400 Subject: [PATCH] switched to an options array --- SVGChartBuilder.php | 84 ++++++++++++++++++++++++++------------------ test-stockMarket.php | 10 ++++-- test-temperature.php | 9 +++-- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/SVGChartBuilder.php b/SVGChartBuilder.php index 86092d3..47a1855 100644 --- a/SVGChartBuilder.php +++ b/SVGChartBuilder.php @@ -2,7 +2,17 @@ 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 $previousY = $previousY = null; end($chartData); @@ -40,33 +50,35 @@ class SVGChartBuilder { $yRange = $yMax - $yMin; $averageAbsSlope /= $yRange * $deltaX; // turn this absolute-deltas total into a slope - // take all these slopes and average them with their neighbors - // unless they change direction, then make them zero - // also restrict them a bit when they are very different - $previousSecant = $previousX = null; - foreach ($secants as $x => $secant) { - if (!is_null($previousSecant)) { - $tangents[$x] = ($secant + $previousSecant) / 2; - if ($secant == 0 || $previousSecant == 0 || $secant * $previousSecant <= 0) - { - $tangents[$x] = 0; - } else { - if ($tangents[$x] / $previousSecant > 3) { - $tangents[$x] = 3 * $previousSecant; - } else if ($tangents[$x] / $secant > 3) { - $tangents[$x] = 3 * $secant; + if ($smoothed) { + // take all these slopes and average them with their neighbors + // unless they change direction, then make them zero + // also restrict them a bit when they are very different + $previousSecant = $previousX = null; + foreach ($secants as $x => $secant) { + if (!is_null($previousSecant)) { + $tangents[$x] = ($secant + $previousSecant) / 2; + if ($secant == 0 || $previousSecant == 0 || $secant * $previousSecant <= 0) + { + $tangents[$x] = 0; + } else { + if ($tangents[$x] / $previousSecant > 3) { + $tangents[$x] = 3 * $previousSecant; + } else if ($tangents[$x] / $secant > 3) { + $tangents[$x] = 3 * $secant; + } } } - } - if ($x == $xMax) { - $tangents[$x] = $secant; - } - if ($x == $xMin) { - $tangents[$x] = $secant; - } + if ($x == $xMax) { + $tangents[$x] = $secant; + } + if ($x == $xMin) { + $tangents[$x] = $secant; + } - $previousX = $x; - $previousSecant = $secant; + $previousX = $x; + $previousSecant = $secant; + } } /* @@ -114,18 +126,20 @@ class SVGChartBuilder { transformX($x, $xMin, $xRange, $width).",". transformY($y, $yMax, $yRange, $height) . "\n"; - $controlX = $deltaX / 3 / sqrt(1 + $tangents[$x]**2); - $controlY = $tangents[$x] * $controlX; - if ($x != $xMin) { - $chartSplines .= " S". - transformX($x - $controlX, $xMin, $xRange, $width).",". - transformY($y - $controlY, $yMax, $yRange, $height)." ". - transformX($x, $xMin, $xRange, $width).",". - transformY($y, $yMax, $yRange, $height); + if ($smoothed) { + $controlX = $deltaX / 3 / sqrt(1 + $tangents[$x]**2); + $controlY = $tangents[$x] * $controlX; + if ($x != $xMin) { + $chartSplines .= " S". + transformX($x - $controlX, $xMin, $xRange, $width).",". + transformY($y - $controlY, $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; $labelModulation = 10 ** (1 + floor(-log($yRange / $numLabels, 10))); @@ -192,7 +206,7 @@ class SVGChartBuilder { .chart__gridLines { font-family: sans-serif; font-size: 10; - fill: '.( $gridLabelColor ).'; + fill: '.( $labelColor ).'; text-anchor: end; shape-rendering: crispEdges; } diff --git a/test-stockMarket.php b/test-stockMarket.php index 8d8345e..2a44f81 100644 --- a/test-stockMarket.php +++ b/test-stockMarket.php @@ -20,7 +20,7 @@ spl_autoload_register(function ($class_name) { $chartData = []; $offset = 100 * (rand()/getRandMax())**4; -$scale = 100 * (rand()/getRandMax())**4; +$scale = 100 * (rand()/getRandMax())**2; $volatility = 0.5 * (rand()/getRandMax())**3; 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; } -print SVGChartBuilder::renderStockChart($chartData, 1000, "#708", "#777", false); +print SVGChartBuilder::renderStockChart($chartData, [ + 'width'=>1000, + 'height'=>250, + 'lineColor'=>"#708", + 'labelColor'=>"#777", + 'smoothed'=>false +]); diff --git a/test-temperature.php b/test-temperature.php index 723955f..93cbfb5 100644 --- a/test-temperature.php +++ b/test-temperature.php @@ -20,7 +20,7 @@ spl_autoload_register(function ($class_name) { $chartData = []; $start = 100 * (rand()/getRandMax())**3; -$volatility = rand()/getRandMax(); +$volatility = rand()/getRandMax() + 0.01; $velocity = (rand()/getRandMax() - 0.5); $acceleration = 0.1 * (rand()/getRandMax())**2; @@ -31,4 +31,9 @@ for ($n = 0, $current = $start; $n < 24; $n++) { $chartData[$n] = $current; } -print SVGChartBuilder::renderStockChart($chartData, 1000, "#708", "#777", true); +print SVGChartBuilder::renderStockChart($chartData, [ + 'width'=>1000, + 'lineColor'=>"#708", + 'labelColor'=>"#777", + 'smoothed'=>true +]);