mirror of
https://github.com/seigler/neat-charts
synced 2025-07-27 01:16:09 +00:00
horrible blob checkin
I changed to an options object, and found a cleaner way to merge defaults and passed options. I renamed and reorganized the demo files.
This commit is contained in:
parent
c6a1a48910
commit
481dd6747b
6 changed files with 317 additions and 228 deletions
|
@ -1,56 +1,109 @@
|
|||
<?php
|
||||
|
||||
class SVGChartBuilder {
|
||||
private $options = [
|
||||
'width' => 800,
|
||||
'height' => 250,
|
||||
'lineColor' => '#000',
|
||||
'labelColor' => '#000',
|
||||
'smoothed' => false,
|
||||
'fontSize' => 15
|
||||
];
|
||||
|
||||
public static function renderStockChart($chartData, $options) {
|
||||
function arrayGet($array, $key, $default = NULL)
|
||||
private $width;
|
||||
private $height;
|
||||
private $output;
|
||||
private $xMin;
|
||||
private $xMax;
|
||||
private $xRange;
|
||||
private $yMin;
|
||||
private $yMax;
|
||||
private $yRange;
|
||||
private $padding = ['top'=>10, 'right'=>10, 'bottom'=>10, 'left'=>10];
|
||||
|
||||
private 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);
|
||||
private function labelFormat($float, $places, $minPlaces = 0) {
|
||||
$value = number_format($float, max($minPlaces, $places));
|
||||
// add a trailing space if there's no decimal
|
||||
return (strpos($value, '.') === false ? $value . '.' : $value);
|
||||
}
|
||||
|
||||
/* Transform data coords to chart coords */
|
||||
/* Transform data coords to chart coords */
|
||||
private function transformX($x) {
|
||||
return round(
|
||||
($x - $this->xMin) / $this->xRange * $this->width
|
||||
, 2);
|
||||
}
|
||||
private function transformY($y) {
|
||||
return round(
|
||||
// SVG has y axis reversed, 0 is at the top
|
||||
($this->yMax - $y) / $this->yRange * $this->height
|
||||
, 2);
|
||||
}
|
||||
|
||||
private function getPrecision($value) { // thanks http://stackoverflow.com/a/21788335/5402566
|
||||
if (!is_numeric($value)) { return false; }
|
||||
$decimal = $value - floor($value); //get the decimal portion of the number
|
||||
if ($decimal == 0) { return 0; } //if it's a whole number
|
||||
$precision = strlen(trim(number_format($decimal,10),'0')) - 1; //-2 to account for '0.'
|
||||
return $precision;
|
||||
}
|
||||
|
||||
public function __construct($chartData, $options) {
|
||||
$this->setOptions($options);
|
||||
$this->setData($chartData);
|
||||
}
|
||||
|
||||
public function setOptions($options) {
|
||||
$this->options = array_replace($this->options, $options);
|
||||
$this->padding['left'] = $this->options['fontSize'] * 5;
|
||||
$this->padding['top'] = $this->padding['bottom'] = $this->options['fontSize'];
|
||||
}
|
||||
|
||||
public function setData($chartData) {
|
||||
// we assume $chartData is sorted by key and keys and values are all numeric
|
||||
$previousY = $previousY = null;
|
||||
$previousX = $previousY = null;
|
||||
end($chartData);
|
||||
$xMax = key($chartData);
|
||||
$this->xMax = key($chartData);
|
||||
reset($chartData);
|
||||
$xMin = key($chartData);
|
||||
$xRange = $xMax - $xMin;
|
||||
$this->xMin = key($chartData);
|
||||
$this->xRange = $this->xMax - $this->xMin;
|
||||
$count = count($chartData);
|
||||
$deltaX = $xRange / $count;
|
||||
$yMin = INF; // so the first comparison sets this to an actual value
|
||||
$yMax = -INF;
|
||||
$deltaX = $this->xRange / $count;
|
||||
$this->yMin = INF; // so the first comparison sets this to an actual value
|
||||
$this->yMax = -INF;
|
||||
$averageAbsSlope = 0; // we will add all of them then divide to get an average
|
||||
$secants = []; // slope between this point and the previous one
|
||||
$tangents = []; // slope across the point
|
||||
|
||||
foreach ($chartData as $x => $y) {
|
||||
if ($y < $yMin) {
|
||||
$yMin = $y;
|
||||
if ($y < $this->yMin) {
|
||||
$this->yMin = $y;
|
||||
$yMinX = $x;
|
||||
}
|
||||
if ($y > $yMax) {
|
||||
$yMax = $y;
|
||||
if ($y > $this->yMax) {
|
||||
$this->yMax = $y;
|
||||
$yMaxX = $x;
|
||||
}
|
||||
if (!is_null($previousY)) {
|
||||
$averageAbsSlope += abs($y - $previousY); // just add up all the Y differences
|
||||
$secants[$previousX] = ($y - $previousY) / $deltaX;
|
||||
}
|
||||
if ($x == $xMax) {
|
||||
if ($x == $this->xMax) {
|
||||
$secants[$x] = ($y - $previousY) / $deltaX;
|
||||
}
|
||||
$previousY = $y;
|
||||
$previousX = $x;
|
||||
}
|
||||
$yRange = $yMax - $yMin;
|
||||
$averageAbsSlope /= $yRange * $deltaX; // turn this absolute-deltas total into a slope
|
||||
$this->yRange = $this->yMax - $this->yMin;
|
||||
$averageAbsSlope /= $this->yRange * $deltaX; // turn this absolute-deltas total into a slope
|
||||
|
||||
if ($smoothed) {
|
||||
if ($this->options['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
|
||||
|
@ -69,10 +122,10 @@ class SVGChartBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ($x == $xMax) {
|
||||
if ($x == $this->xMax) {
|
||||
$tangents[$x] = $secant;
|
||||
}
|
||||
if ($x == $xMin) {
|
||||
if ($x == $this->xMin) {
|
||||
$tangents[$x] = $secant;
|
||||
}
|
||||
|
||||
|
@ -88,60 +141,41 @@ class SVGChartBuilder {
|
|||
http://vis4.net/blog/posts/doing-the-line-charts-right/
|
||||
*/
|
||||
$aspectRatio = max(0.25, min(0.75, 1 / $averageAbsSlope));
|
||||
$height = (is_null($height) ? floor($aspectRatio * $width) : $height);
|
||||
|
||||
function labelFormat($float, $places, $minPlaces = 0) {
|
||||
$value = number_format($float, max($minPlaces, $places));
|
||||
// add a trailing space if there's no decimal
|
||||
return (strpos($value, ".") === false ? $value . "." : $value);
|
||||
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
||||
if (isset($this->options['height'])) {
|
||||
$this->height = $this->options['height'] - $this->padding['top'] - $this->padding['bottom'];
|
||||
} else {
|
||||
$this->height = floor($aspectRatio * $this->width);
|
||||
$this->options['height'] = $this->height + $this->padding['top'] + $this->padding['bottom'];
|
||||
}
|
||||
|
||||
/* Transform data coords to chart coords */
|
||||
function transformX($x, $xMin, $xRange, $width) {
|
||||
return round(
|
||||
($x - $xMin) / $xRange * $width
|
||||
, 2);
|
||||
}
|
||||
function transformY($y, $yMax, $yRange, $height) {
|
||||
return round(
|
||||
// SVG has y axis reversed, 0 is at the top
|
||||
($yMax - $y) / $yRange * $height
|
||||
, 2);
|
||||
}
|
||||
|
||||
function getPrecision($value) { // thanks http://stackoverflow.com/a/21788335/5402566
|
||||
if (!is_numeric($value)) { return false; }
|
||||
$decimal = $value - floor($value); //get the decimal portion of the number
|
||||
if ($decimal == 0) { return 0; } //if it's a whole number
|
||||
$precision = strlen(trim(number_format($decimal,10),"0")) - 1; //-2 to account for "0."
|
||||
return $precision;
|
||||
}
|
||||
|
||||
$chartPoints = "M";
|
||||
$chartSplines = "M".
|
||||
transformX($xMin, $xMin, $xRange, $width).",".
|
||||
transformY($chartData[$xMin], $yMax, $yRange, $height);
|
||||
$chartPoints = 'M';
|
||||
$chartSplines = 'M'.
|
||||
$this->transformX($this->xMin).','.
|
||||
$this->transformY($chartData[$this->xMin]);
|
||||
if ($this->options['smoothed']) {
|
||||
foreach ($chartData as $x => $y) {
|
||||
$chartPoints .=
|
||||
transformX($x, $xMin, $xRange, $width).",".
|
||||
transformY($y, $yMax, $yRange, $height) . "\n";
|
||||
|
||||
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);
|
||||
if ($x != $this->xMin) {
|
||||
$chartSplines .= ' S'.
|
||||
$this->transformX($x - $controlX).','.
|
||||
$this->transformY($y - $controlY).' '.
|
||||
$this->transformX($x).','.
|
||||
$this->transformY($y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
foreach ($chartData as $x => $y) {
|
||||
$chartPoints .=
|
||||
$this->transformX($x).','.
|
||||
$this->transformY($y) . ' ';
|
||||
}
|
||||
}
|
||||
|
||||
$numLabels = 2 + ceil($height / 60);
|
||||
$labelInterval = $yRange / $numLabels;
|
||||
$labelModulation = 10 ** (1 + floor(-log($yRange / $numLabels, 10)));
|
||||
$numLabels = 2 + ceil($this->height / $this->options['fontSize'] / 6);
|
||||
$labelInterval = $this->yRange / $numLabels;
|
||||
$labelModulation = 10 ** (1 + floor(-log($this->yRange / $numLabels, 10)));
|
||||
|
||||
// 0.1 here is a fudge factor so we get multiples of 2.5 a little more often
|
||||
if (fmod($labelInterval * $labelModulation, 2.5) < fmod($labelInterval * $labelModulation, 2) + 0.1) {
|
||||
|
@ -150,90 +184,93 @@ class SVGChartBuilder {
|
|||
$labelModulation /= 2;
|
||||
}
|
||||
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
|
||||
$labelPrecision = getPrecision($labelInterval);
|
||||
$labelPrecision = $this->getPrecision($labelInterval);
|
||||
|
||||
// Top and bottom grid lines
|
||||
$gridLines =
|
||||
"M10,0 ".$width.",0\n".
|
||||
"M10,".$height.",".$width.",".$height."\n";
|
||||
'M10,0 '.$this->width.',0 '.
|
||||
' M10,'.$this->height.','.$this->width.','.$this->height;
|
||||
|
||||
// Top and bottom grid labels
|
||||
$gridText =
|
||||
'<text x="6" y="4">'.labelFormat($yMax, $labelPrecision + 1).'</text>' .
|
||||
'<text x="6" y="'.($height + 4).'">'.labelFormat($yMin, $labelPrecision + 1).'</text>';
|
||||
'<text x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] / 2).'">'.($this->labelFormat($this->yMax, $labelPrecision + 1)).'</text>' .
|
||||
'<text x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] / 2 + $this->height).'">'.($this->labelFormat($this->yMin, $labelPrecision + 1)).'</text>';
|
||||
|
||||
// Main labels and grid lines
|
||||
for (
|
||||
$labelY = $yMin - fmod($yMin, $labelInterval) + $labelInterval; // Start at the first "nice" Y value > min
|
||||
$labelY < $yMax; // Keep going until max
|
||||
$labelY = $this->yMin - fmod($this->yMin, $labelInterval) + $labelInterval; // Start at the first "nice" Y value > min
|
||||
$labelY < $this->yMax; // Keep going until max
|
||||
$labelY += $labelInterval // Add Interval each iteration
|
||||
) {
|
||||
$labelHeight = transformY($labelY, $yMax, $yRange, $height);
|
||||
$labelHeight = $this->transformY($labelY);
|
||||
if ( // label is not too close to the min or max
|
||||
$labelHeight < $height - 25 &&
|
||||
$labelHeight > 25
|
||||
$labelHeight < $this->height - 2.5 * $this->options['fontSize'] &&
|
||||
$labelHeight > $this->options['fontSize'] * 2.5
|
||||
) {
|
||||
$gridText .= '<text x="-4" y="'.($labelHeight + 4).'">'.labelFormat($labelY, $labelPrecision).'</text>';
|
||||
$gridLines .= " M0,".$labelHeight." ".$width.",".$labelHeight;
|
||||
$gridText .= '<text x="-'.(0.25 * $this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] / 2).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>';
|
||||
$gridLines .= ' M0,'.$labelHeight.' '.$this->width.','.$labelHeight;
|
||||
} else if ( // label is too close
|
||||
$labelHeight < $height - 4 &&
|
||||
$labelHeight > 4
|
||||
$labelHeight < $this->height - $this->options['fontSize'] / 2 &&
|
||||
$labelHeight > $this->options['fontSize'] / 2
|
||||
) {
|
||||
$gridLines .= " M".( // move grid line over when it's very close to the min or max label
|
||||
$labelHeight < $height - 10 && $labelHeight > 10 ? 0 : 10
|
||||
).",".$labelHeight." ".$width.",".$labelHeight;
|
||||
$gridLines .= ' M'.( // move grid line over when it's very close to the min or max label
|
||||
$labelHeight < $this->height - $this->options['fontSize'] / 2 && $labelHeight > $this->options['fontSize'] / 2 ? 0 : $this->options['fontSize'] / 2
|
||||
).','.$labelHeight.' '.$this->width.','.$labelHeight;
|
||||
}
|
||||
}
|
||||
|
||||
print '<?xml version="1.0" standalone="no"?>
|
||||
<svg
|
||||
viewBox="-90 -10 '.( $width + 100 ).' '.( $height + 20 ).'"
|
||||
width="'.( $width + 100 ).'"
|
||||
height="'.( $height + 20 ).'"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
$chartID = rand();
|
||||
$this->output = '<?xml version="1.0" standalone="no"?>
|
||||
<svg viewBox="-'.( $this->padding['left'] ).' -'.( $this->padding['top'] ).' '.( $this->options['width'] ).' '.( $this->options['height'] ).'" width="'.( $this->options['width'] ).'" height="'.( $this->options['height'] ).'" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<marker id="markerCircle" markerWidth="2" markerHeight="2" refX="1" refY="1" markerUnits="strokeWidth">
|
||||
<circle cx="1" cy="1" r="1" style="stroke: none; fill:#000000;"/>
|
||||
<marker id="SVGChart-markerCircle-'.( $chartID ).'" markerWidth="2" markerHeight="2" refX="1" refY="1" markerUnits="strokeWidth">
|
||||
<circle cx="1" cy="1" r="1" style="stroke: none; fill:'.( $this->options['lineColor'] ).';" />
|
||||
</marker>
|
||||
<linearGradient id="fadeFromNothing" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0.5%" stop-color="'.( $lineColor ).'" stop-opacity="0"></stop>
|
||||
<stop offset="5%" stop-color="'.( $lineColor ).'" stop-opacity="1"></stop>
|
||||
<stop offset="100%" stop-color="'.( $lineColor ).'" stop-opacity="1"></stop>
|
||||
<linearGradient id="SVGChart-fadeFromNothing-'.( $chartID ).'" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0.5%" stop-color="'.( $this->options['lineColor'] ).'" stop-opacity="0"></stop>
|
||||
<stop offset="5%" stop-color="'.( $this->options['lineColor'] ).'" stop-opacity="1"></stop>
|
||||
<stop offset="100%" stop-color="'.( $this->options['lineColor'] ).'" stop-opacity="1"></stop>
|
||||
</linearGradient>
|
||||
<style type="text/css"><![CDATA[
|
||||
.chart__gridLines {
|
||||
<style type="text/css">
|
||||
<![CDATA[ .SVGChart-'.( $chartID ).' .chart__gridLines {
|
||||
font-family: sans-serif;
|
||||
font-size: 10;
|
||||
fill: '.( $labelColor ).';
|
||||
font-size: '.( $this->options['fontSize'] ).'px;
|
||||
fill: '.( $this->options['labelColor'] ).';
|
||||
text-anchor: end;
|
||||
shape-rendering: crispEdges;
|
||||
}
|
||||
.chart__gridLinePaths {
|
||||
|
||||
.SVGChart-'.( $chartID ).' .chart__gridLinePaths {
|
||||
fill: none;
|
||||
stroke: #000000;
|
||||
stroke: '.( $this->options['labelColor'] ).';
|
||||
stroke-opacity: 0.75;
|
||||
stroke-width: 1;
|
||||
stroke-dasharray: 2, 2;
|
||||
stroke-opacity: 0.25;
|
||||
}
|
||||
.chart__plotLine {
|
||||
|
||||
.SVGChart-'.( $chartID ).' .chart__plotLine {
|
||||
fill: none;
|
||||
stroke-width: 5;
|
||||
stroke-width: '.( $this->options['fontSize'] / 3 ).';
|
||||
stroke-linejoin: round;
|
||||
stroke-linecap: round;
|
||||
stroke: url(#fadeFromNothing);
|
||||
marker-end: url(#markerCircle);
|
||||
stroke: url(#SVGChart-fadeFromNothing-'.( $chartID ).');
|
||||
marker-end: url(#SVGChart-markerCircle-'.( $chartID ).');
|
||||
}
|
||||
]]></style>
|
||||
|
||||
]]>
|
||||
</style>
|
||||
</defs>
|
||||
<g class="SVGChart SVGChart-'.( $chartID ).'">
|
||||
<g class="chart__gridLines">
|
||||
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" />
|
||||
'.( $gridText ).'
|
||||
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" /> '.( $gridText ).'
|
||||
</g>
|
||||
<g class="chart__plotLine">
|
||||
<path d="'.( $smoothed ? $chartSplines : $chartPoints ).'" />
|
||||
<path d="'.( $this->options['smoothed'] ? $chartSplines : $chartPoints ).'" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>';
|
||||
}
|
||||
public function render() {
|
||||
return $this->output;
|
||||
}
|
||||
}
|
||||
|
|
21
Util.php
21
Util.php
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
class Util {
|
||||
public static function getJson($url) {
|
||||
if (empty($url)) {
|
||||
trigger_error('Missing or empty JSON url');
|
||||
}
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
|
||||
# curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
# curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
# curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/VeriSignClass3PublicPrimaryCertificationAuthority-G5.pem");
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$result = json_decode($result) or trigger_error('Couldn\'t parse JSON');
|
||||
return $result;
|
||||
}
|
||||
}
|
93
demo.php
Normal file
93
demo.php
Normal file
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
|
||||
<title>SVGChartBuilder demo</title>
|
||||
<style>
|
||||
main {
|
||||
-webkit-columns: 800px 2;
|
||||
-moz-columns: 800px 2;
|
||||
columns: 800px 2;
|
||||
}
|
||||
section {
|
||||
display: inline-block;
|
||||
width: auto;
|
||||
max-width: 800px;
|
||||
padding: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<section>
|
||||
<h2>Poloniex Dash/BTC Price</h2>
|
||||
<img src="poloniex-dash-btc.php" alt="Poloniex Dash/BTC price">
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Fake Stock Market Data</h2>
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
spl_autoload_register(function ($class_name) {
|
||||
include $class_name . ".php";
|
||||
});
|
||||
|
||||
// fake up some stock market data
|
||||
|
||||
$chartData = [];
|
||||
|
||||
$offset = 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++) {
|
||||
$current -= $offset;
|
||||
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
||||
$current += $offset;
|
||||
$chartData[$n] = $current;
|
||||
}
|
||||
|
||||
$stockChart = new SVGChartBuilder($chartData, [
|
||||
"width"=>500,
|
||||
"height"=>150,
|
||||
"fontSize"=>10
|
||||
]);
|
||||
print $stockChart->render();
|
||||
?>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Monotonically Smoothed Chart</h2>
|
||||
<?php
|
||||
$chartData = [];
|
||||
|
||||
$start = 100 * (rand()/getRandMax())**3;
|
||||
$volatility = rand()/getRandMax() + 0.01;
|
||||
$velocity = (rand()/getRandMax() - 0.5);
|
||||
$acceleration = 0.1 * (rand()/getRandMax())**2;
|
||||
|
||||
for ($n = 0, $current = $start; $n < 12; $n++) {
|
||||
$velocity *= 0.5;
|
||||
$velocity += $acceleration * 2 * (rand()/getRandMax() - 0.5);
|
||||
$current += $velocity;
|
||||
$chartData[$n] = $current;
|
||||
}
|
||||
|
||||
$tempChart = new SVGChartBuilder($chartData, [
|
||||
"width"=>700,
|
||||
"height"=>400,
|
||||
"lineColor"=>"#D00",
|
||||
"labelColor"=>"#777",
|
||||
"smoothed"=>true
|
||||
]);
|
||||
print $tempChart->render();
|
||||
?>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
34
index.php
34
index.php
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
//ini_set('display_errors', 1);
|
||||
|
||||
Header('Content-type: image/svg+xml; charset=utf-8');
|
||||
Header('Content-Disposition: inline; filename="Dash-24h-chart-' . date('Y-m-d\THisT') . '.svg"');
|
||||
include 'buffer.php';
|
||||
|
||||
spl_autoload_register(function ($class_name) {
|
||||
include $class_name . '.php';
|
||||
});
|
||||
|
||||
$yesterday = time() - (24 * 60 * 60);
|
||||
$poloniex_url = 'https://poloniex.com/public?command=returnChartData¤cyPair=BTC_DASH&start=' . $yesterday . '&end=9999999999&period=' .
|
||||
//300 //5 min
|
||||
900 //15 min
|
||||
//1800 //30 min
|
||||
//7200 //3h
|
||||
//14400 //6h
|
||||
//86400 //1d
|
||||
;
|
||||
$last24h = Util::getJson($poloniex_url);
|
||||
$chartData = [];
|
||||
|
||||
foreach ($last24h as $item) {
|
||||
$chartData[$item->date] = $item->weightedAverage;
|
||||
}
|
||||
|
||||
print SVGChartBuilder::renderStockChart($chartData, [
|
||||
'width'=>800,
|
||||
'height'=>250,
|
||||
'lineColor'=>"#1C75BC",
|
||||
'labelColor'=>"#777",
|
||||
'smoothed'=>false
|
||||
]);
|
53
poloniex-dash-btc.php
Normal file
53
poloniex-dash-btc.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
//ini_set('display_errors', 1);
|
||||
|
||||
Header('Content-type: image/svg+xml; charset=utf-8');
|
||||
Header('Content-Disposition: inline; filename="Dash-24h-chart-' . date('Y-m-d\THisT') . '.svg"');
|
||||
include 'buffer.php';
|
||||
|
||||
spl_autoload_register(function ($class_name) {
|
||||
include $class_name . ".php";
|
||||
});
|
||||
|
||||
function getJson($url) {
|
||||
if (empty($url)) {
|
||||
trigger_error('Missing or empty JSON url');
|
||||
}
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
|
||||
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
|
||||
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
// curl_setopt($ch, CURLOPT_CAINFO, getcwd() . "/VeriSignClass3PublicPrimaryCertificationAuthority-G5.pem");
|
||||
|
||||
$result = curl_exec($ch);
|
||||
$result = json_decode($result) or trigger_error('Couldn\'t parse JSON');
|
||||
return $result;
|
||||
}
|
||||
|
||||
$yesterday = time() - (24 * 60 * 60);
|
||||
$poloniex_url = 'https://poloniex.com/public?command=returnChartData¤cyPair=BTC_DASH&start=' . $yesterday . '&end=9999999999&period=' .
|
||||
//300 //5 min
|
||||
900 //15 min
|
||||
//1800 //30 min
|
||||
//7200 //3h
|
||||
//14400 //6h
|
||||
//86400 //1d
|
||||
;
|
||||
$last24h = getJson($poloniex_url);
|
||||
$chartData = [];
|
||||
|
||||
foreach ($last24h as $item) {
|
||||
$chartData[$item->date] = $item->weightedAverage;
|
||||
}
|
||||
|
||||
$poloniexChart = new SVGChartBuilder($chartData, [
|
||||
'width'=>800,
|
||||
'height'=>250,
|
||||
'lineColor'=>"#1C75BC", // Dash blue
|
||||
'labelColor'=>"#777",
|
||||
'smoothed'=>false
|
||||
]);
|
||||
print $poloniexChart->render();
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
/*
|
||||
|
||||
This file is intended to be a testing ground in case
|
||||
you want to adjust the parameters of these charts.
|
||||
That way you can make lots of changes without
|
||||
hammering Poloniex half to death.
|
||||
|
||||
*/
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
//include 'buffer.php';
|
||||
|
||||
Header('Content-type: image/svg+xml; charset=utf-8');
|
||||
|
||||
spl_autoload_register(function ($class_name) {
|
||||
include $class_name . '.php';
|
||||
});
|
||||
|
||||
$chartData = [];
|
||||
|
||||
$offset = 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++) {
|
||||
$current -= $offset;
|
||||
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
||||
$current += $offset;
|
||||
$chartData[$n] = $current;
|
||||
}
|
||||
|
||||
print SVGChartBuilder::renderStockChart($chartData, [
|
||||
'width'=>1000,
|
||||
'height'=>250,
|
||||
'lineColor'=>"#708",
|
||||
'labelColor'=>"#777",
|
||||
'smoothed'=>false
|
||||
]);
|
Loading…
Add table
Add a link
Reference in a new issue