mirror of
https://github.com/seigler/neat-charts
synced 2025-07-27 09:26:10 +00:00
improved readme, added demo of PNG generation
This commit is contained in:
parent
da27fc818e
commit
352794cbfc
3 changed files with 104 additions and 40 deletions
15
README.md
15
README.md
|
@ -9,17 +9,22 @@ PHP project to generate clean-looking SVG price charts
|
||||||
* PHP
|
* PHP
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
Extract the files from https://github.com/seigler/Dash-SVG-chart/archive/master.zip where you want to use the chart, or from the command line run `git clone "https://github.com/seigler/Dash-SVG-chart" .` in the folder where you want the charts served from.
|
Best:
|
||||||
|
add a composer dependency on `seigler/neat-charts`.
|
||||||
|
|
||||||
|
Next best:
|
||||||
|
Copy the how it's done in `/demo/index.php`.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
In your PHP file:
|
With Composer:
|
||||||
|
`composer require seigler/neat-charts`
|
||||||
|
|
||||||
|
In your PHP file:
|
||||||
```php
|
```php
|
||||||
<?php
|
<?php
|
||||||
Header('Content-type: image/svg+xml; charset=utf-8');
|
Header('Content-type: image/svg+xml; charset=utf-8');
|
||||||
Header('Content-Disposition: inline; filename="chart-' . date('Y-m-d\THisT') . '.svg"');
|
Header('Content-Disposition: inline; filename="chart-' . date('Y-m-d\THisT') . '.svg"');
|
||||||
require 'buffer.php'; // feel free to use your own caching instead of this one in the demo folder
|
require 'NeatCharts/LineChart.php'; // better to use composer, require "seigler/neat-charts".
|
||||||
require 'NeatCharts/LineChart.php'; // better to use composer, require "seigler/NeatCharts".
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
your code here to populate $chartData
|
your code here to populate $chartData
|
||||||
|
@ -40,5 +45,5 @@ In your HTML:
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
* PHP output buffering based on http://www.the-art-of-web.com/php/buffer/
|
* Demo's output caching based on http://www.the-art-of-web.com/php/buffer/
|
||||||
* Chart appearance based on advice found at http://vis4.net/blog/posts/doing-the-line-charts-right/
|
* Chart appearance based on advice found at http://vis4.net/blog/posts/doing-the-line-charts-right/
|
||||||
|
|
66
demo/poloniex-dash-btc-png.php
Normal file
66
demo/poloniex-dash-btc-png.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
//ini_set('display_errors', 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Display a 7 day Dash/BTC chart from Poloniex as a PNG (converted from SVG by imageMagick)
|
||||||
|
requires the imagick module be installed
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
header("Content-Type: image/png");
|
||||||
|
header('Content-Disposition: inline; filename="Dash-24h-chart-' . date('Y-m-d\THisT') . '.png"');
|
||||||
|
require 'buffer.php';
|
||||||
|
require '../src/NeatCharts/LineChart.php'; // really just use composer instead
|
||||||
|
|
||||||
|
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() - (7 * 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 NeatCharts\LineChart($chartData, [
|
||||||
|
'width'=>800,
|
||||||
|
'height'=>200,
|
||||||
|
'lineColor'=>"#1C75BC", // Dash blue
|
||||||
|
'labelColor'=>"#777",
|
||||||
|
'smoothed'=>false,
|
||||||
|
'fontSize'=>10
|
||||||
|
]);
|
||||||
|
$svg = $poloniexChart->render();
|
||||||
|
|
||||||
|
$im = new Imagick();
|
||||||
|
$im->setBackgroundColor(new ImagickPixel("transparent"));
|
||||||
|
$im->readImageBlob($svg);
|
||||||
|
$im->setImageFormat("png32");
|
||||||
|
echo $im;
|
||||||
|
$im->clear();
|
||||||
|
$im->destroy();
|
|
@ -193,8 +193,8 @@ namespace NeatCharts {
|
||||||
|
|
||||||
// Top and bottom grid labels
|
// Top and bottom grid labels
|
||||||
$gridText =
|
$gridText =
|
||||||
'<text x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] * 0.4).'">'.($this->labelFormat($this->yMax, $labelPrecision + 1)).'</text>' .
|
'<text text-anchor="end" x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] * 0.4).'">'.($this->labelFormat($this->yMax, $labelPrecision + 1)).'</text>' .
|
||||||
'<text x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] * 0.4 + $this->height).'">'.($this->labelFormat($this->yMin, $labelPrecision + 1)).'</text>';
|
'<text text-anchor="end" x="'.(0.4 * $this->options['fontSize']).'" y="'.($this->options['fontSize'] * 0.4 + $this->height).'">'.($this->labelFormat($this->yMin, $labelPrecision + 1)).'</text>';
|
||||||
|
|
||||||
// Main labels and grid lines
|
// Main labels and grid lines
|
||||||
for (
|
for (
|
||||||
|
@ -207,7 +207,7 @@ namespace NeatCharts {
|
||||||
$labelHeight < $this->height - 1.5 * $this->options['fontSize'] &&
|
$labelHeight < $this->height - 1.5 * $this->options['fontSize'] &&
|
||||||
$labelHeight > $this->options['fontSize'] * 1.5
|
$labelHeight > $this->options['fontSize'] * 1.5
|
||||||
) {
|
) {
|
||||||
$gridText .= '<text x="-'.(0.25 * $this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] * 0.4).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>';
|
$gridText .= '<text text-anchor="end" x="-'.(0.25 * $this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] * 0.4).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>';
|
||||||
$gridLines .= ' M0,'.$labelHeight.' '.$this->width.','.$labelHeight;
|
$gridLines .= ' M0,'.$labelHeight.' '.$this->width.','.$labelHeight;
|
||||||
} else if ( // label is too close
|
} else if ( // label is too close
|
||||||
$labelHeight < $this->height - $this->options['fontSize'] * 0.75 &&
|
$labelHeight < $this->height - $this->options['fontSize'] * 0.75 &&
|
||||||
|
@ -231,40 +231,33 @@ namespace NeatCharts {
|
||||||
<stop offset="5%" stop-color="'.( $this->options['lineColor'] ).'" stop-opacity="1"></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>
|
<stop offset="100%" stop-color="'.( $this->options['lineColor'] ).'" stop-opacity="1"></stop>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<style type="text/css">
|
|
||||||
<![CDATA[ .SVGChart-'.( $chartID ).' .chart__gridLines {
|
|
||||||
font-family: sans-serif;
|
|
||||||
font-size: '.( $this->options['fontSize'] ).'px;
|
|
||||||
fill: '.( $this->options['labelColor'] ).';
|
|
||||||
text-anchor: end;
|
|
||||||
shape-rendering: crispEdges;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SVGChart-'.( $chartID ).' .chart__gridLinePaths {
|
|
||||||
fill: none;
|
|
||||||
stroke: '.( $this->options['labelColor'] ).';
|
|
||||||
stroke-opacity: 0.75;
|
|
||||||
stroke-width: 1;
|
|
||||||
stroke-dasharray: 2, 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.SVGChart-'.( $chartID ).' .chart__plotLine {
|
|
||||||
fill: none;
|
|
||||||
stroke-width: '.( $this->options['fontSize'] / 3 ).';
|
|
||||||
stroke-linejoin: round;
|
|
||||||
stroke-linecap: round;
|
|
||||||
stroke: url(#SVGChart-fadeFromNothing-'.( $chartID ).');
|
|
||||||
marker-end: url(#SVGChart-markerCircle-'.( $chartID ).');
|
|
||||||
}
|
|
||||||
|
|
||||||
]]>
|
|
||||||
</style>
|
|
||||||
</defs>
|
</defs>
|
||||||
<g class="SVGChart SVGChart-'.( $chartID ).'">
|
<g class="SVGChart">
|
||||||
<g class="chart__gridLines">
|
<g class="chart__gridLines"
|
||||||
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" /> '.( $gridText ).'
|
shape-rendering="crispEdges"
|
||||||
|
fill="none"
|
||||||
|
stroke="'.( $this->options['labelColor'] ).'"
|
||||||
|
stroke-opacity="0.75"
|
||||||
|
stroke-width="1"
|
||||||
|
stroke-dasharray="2, 2"
|
||||||
|
>
|
||||||
|
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" />
|
||||||
</g>
|
</g>
|
||||||
<g class="chart__plotLine">
|
<g class="chart__gridLabels"
|
||||||
|
fill="'.( $this->options['labelColor'] ).'"
|
||||||
|
font-family="sans-serif"
|
||||||
|
font-size="'.( $this->options['fontSize'] ).'px"
|
||||||
|
>
|
||||||
|
'.( $gridText ).'
|
||||||
|
</g>
|
||||||
|
<g class="chart__plotLine"
|
||||||
|
fill="none"
|
||||||
|
stroke-width="'.( $this->options['fontSize'] / 3 ).'"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke="url(#SVGChart-fadeFromNothing-'.( $chartID ).')"
|
||||||
|
marker-end="url(#SVGChart-markerCircle-'.( $chartID ).')"
|
||||||
|
>
|
||||||
<path d="'.( $this->options['smoothed'] ? $chartSplines : $chartPoints ).'" />
|
<path d="'.( $this->options['smoothed'] ? $chartSplines : $chartPoints ).'" />
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue