Added BAR CHARTS!

This commit is contained in:
Joshua Seigler 2016-07-05 01:49:18 -04:00
parent 603666e167
commit c5f6c0476e
5 changed files with 116 additions and 23 deletions

View file

@ -3,7 +3,11 @@
PHP project to generate clean-looking SVG price charts PHP project to generate clean-looking SVG price charts
![Dash 24h price in BTC from Poloniex](http://cryptohistory.org/charts/dark/dash-btc/30d/svg?lineColor=1C74BC) ![Dash 24h price in BTC from Poloniex](http://cryptohistory.org/charts/dark/dash-btc/30d/svg?lineColor=1C74BC)
7d of Dash price in Bitcoin from Poloniex.com 30 days of Dash price in Bitcoin from Poloniex.com
Ethereum 7-day price in BTC from Poloniex ![Ethereum 7d price in BTC from Poloniex](http://cryptohistory.org/charts/sparkline/eth-btc/7d/svg)
More examples at [cryptohistory.org](http://cryptohistory.org/).
## Requirements ## Requirements
@ -66,6 +70,7 @@ In your HTML:
## Available Options ## Available Options
### LineChart
| Option | Default | | Option | Default |
| --- | --- | | --- | --- |
| width | 800 | | width | 800 |
@ -77,6 +82,21 @@ In your HTML:
| fontSize | 15 | | fontSize | 15 |
| yAxisEnabled | true | | yAxisEnabled | true |
| xAxisEnabled | false | | xAxisEnabled | false |
| yAxisZero | false |
| filled | false |
### BarChart
| Option | Default |
| --- | --- |
| width | 600 |
| height | 300 |
| barColor | '#000' |
| markerColor | '#000' |
| labelColor | '#000' |
| fontSize | 15 |
| yAxisEnabled | true |
| xAxisEnabled | false |
| yAxisZero | true |
## Credits ## Credits

View file

@ -1,11 +1,11 @@
<?php <?php
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
function randomData($count = 96) { function randomData($count = 96, $offsetMax = 100) {
$randomData = []; $randomData = [];
$offset = 100 * (rand()/getRandMax())**2; $offset = $offsetMax * (rand()/getRandMax())**2;
$scale = max(0.1 * $offset, 100 * rand() / getRandMax()); $scale = max(0.25 * $offset, 100 * rand() / getRandMax());
$volatility = 0.25 * (rand()/getRandMax())**3 + 0.25; $volatility = 0.5 * (rand()/getRandMax())**3 + 0.25;
for ($n = 0, $current = $offset + 0.5 * $scale; $n < $count; $n++) { for ($n = 0, $current = $offset + 0.5 * $scale; $n < $count; $n++) {
$current -= $offset; $current -= $offset;
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5); $current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
@ -39,9 +39,9 @@ function randomData($count = 96) {
</figure> </figure>
</section> </section>
<section> <section>
<h2>Chart in <code>svg</code> tag, zero axis shown</h2> <h2>Chart in <code>svg</code> tag, zero axis shown, filled</h2>
<figure> <figure>
<?php <?php
$chart = new NeatCharts\LineChart(randomData(), [ $chart = new NeatCharts\LineChart(randomData(), [
'width'=>800, 'width'=>800,
'height'=>250, 'height'=>250,
@ -49,7 +49,8 @@ $chart = new NeatCharts\LineChart(randomData(), [
'labelColor'=>'#222', 'labelColor'=>'#222',
'smoothed'=>false, 'smoothed'=>false,
'fontSize'=>14, 'fontSize'=>14,
'yAxisZero'=>true 'yAxisZero'=>true,
'filled'=>true
]); ]);
echo $chart->render(); echo $chart->render();
?> ?>
@ -59,10 +60,10 @@ echo $chart->render();
<section> <section>
<h2>Smoothed chart in <code>svg</code> tag</h2> <h2>Smoothed chart in <code>svg</code> tag</h2>
<figure> <figure>
<?php <?php
$chart = new NeatCharts\LineChart(randomData(12), [ $chart = new NeatCharts\LineChart(randomData(12), [
'width'=>300, 'width'=>400,
'height'=>300, 'height'=>300, // null works as a height too, it picks a height that makes the plot look good
'lineColor'=>'#080', 'lineColor'=>'#080',
'labelColor'=>'#222', 'labelColor'=>'#222',
'smoothed'=>true, 'smoothed'=>true,
@ -88,6 +89,18 @@ $chart = new NeatCharts\LineChart(randomData(48), [
'xAxisEnabled'=>false 'xAxisEnabled'=>false
]); ]);
echo $chart->render(); echo $chart->render();
?>
<figcaption>Random generated data, loaded right in the page</figcaption>
</figure>
</section>
<section>
<h2>Bar chart in <code>svg</code> tag</h2>
<figure>
<?php
$chart = new NeatCharts\BarChart(randomData(10, 0), [
'barColor'=>'#409'
]);
echo $chart->render();
?> ?>
<figcaption>Random generated data, loaded right in the page</figcaption> <figcaption>Random generated data, loaded right in the page</figcaption>
</figure> </figure>

View file

@ -0,0 +1,59 @@
<?php
namespace NeatCharts {
class BarChart extends NeatChart {
public function setOptions($options) {
$this->options = [ // BarChart defaults
'width' => 600,
'height' => 300,
'barColor' => '#000',
'markerColor' => '#000',
'labelColor' => '#000',
'fontSize' => 15,
'yAxisEnabled'=>true,
'xAxisEnabled'=>false,
'yAxisZero'=>true
];
parent::setOptions($options);
}
public function setData($chartData) {
$this->setWindow($chartData, $this->options); // sets min, max, range, etc
// we assume $chartData is sorted by key and keys and values are all numeric
$count = count($chartData);
$deltaX = $this->xRange / $count;
$this->xMin -= $deltaX / 2;
$this->xMax += $deltaX / 2;
$this->xRange += $deltaX;
$gridLabelXML = $this->buildGridLabelXML();
// this also sets $this->width and $this->height
$barRadius = min($this->width / $count / 2.5, $this->width / $count / 2 - 1);
$chartPoints = '';
foreach($chartData as $x => $y) {
$barX = $this->transformX($x);
$barY = $this->transformY($y);
$barY0 = $this->transformY(0);
$chartPoints .= ' M'.($barX - $barRadius).','.$barY0.' '.($barX + $barRadius).','.$barY0.' '.($barX + $barRadius).','.$barY.' '.($barX - $barRadius).','.$barY.' Z';
}
$this->output = '<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">
<g class="neatchart">'.
$gridLabelXML.'
<g
class="chart__bars"
fill="'.( $this->options['barColor'] ).'"
fill-opacity="0.5"
stroke="'.( $this->options['barColor'] ).'"
stroke-width="2"
stroke-linecap="round"
>
<path d="'.( $chartPoints ).'" />
</g>
</g>
</svg>';
}
}
}

View file

@ -12,7 +12,8 @@ namespace NeatCharts {
'fontSize' => 15, 'fontSize' => 15,
'yAxisEnabled'=>true, 'yAxisEnabled'=>true,
'xAxisEnabled'=>false, 'xAxisEnabled'=>false,
'yAxisZero'=>false 'yAxisZero'=>false,
'filled'=>false
]; ];
parent::setOptions($options); parent::setOptions($options);
} }
@ -128,7 +129,7 @@ namespace NeatCharts {
stroke="url(#neatchart-fadeFromNothing-'.( $chartID ).')" stroke="url(#neatchart-fadeFromNothing-'.( $chartID ).')"
marker-end="url(#neatchart-markerCircle-'.( $chartID ).')" marker-end="url(#neatchart-markerCircle-'.( $chartID ).')"
> >
<path d="'.( $chartPoints ).'" />'.($this->options['yAxisZero'] ? ' <path d="'.( $chartPoints ).'" />'.($this->options['filled'] ? '
<path <path
stroke="none" stroke="none"
fill="url(#neatchart-fadeFromNothing-'.( $chartID ).')" fill="url(#neatchart-fadeFromNothing-'.( $chartID ).')"

View file

@ -91,20 +91,20 @@ namespace NeatCharts {
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation; $labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
$labelPrecision = $this->getPrecision($labelInterval); $labelPrecision = $this->getPrecision($labelInterval);
$this->padding['left'] = $this->options['fontSize'] * 0.6 * ( $this->padding['left'] = $this->options['fontSize'] * 0.65 * (
1 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval) 2.5 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval)
) + 10; );
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right']; $this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
// Top and bottom grid lines // Top and bottom grid lines
$gridLines = $gridLines =
'M10,0 '.$this->width.',0 '. 'M0,0 '.$this->width.',0 '.
' M10,'.$this->height.','.$this->width.','.$this->height; ' M0,'.$this->height.','.$this->width.','.$this->height;
// Top and bottom grid labels // Top and bottom grid labels
$gridText = $gridText =
'<text text-anchor="end" 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 text-anchor="end" 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 (
@ -117,8 +117,8 @@ 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 text-anchor="end" x="-'.(0.25 * $this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] * 0.4).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>'; $gridText .= '<text text-anchor="end" x="-'.($this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] * 0.4).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>';
$gridLines .= ' M0,'.$labelHeight.' '.$this->width.','.$labelHeight; $gridLines .= ' M-'.($this->options['fontSize'] * 0.65).','.$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 &&
$labelHeight > $this->options['fontSize'] * 0.75 $labelHeight > $this->options['fontSize'] * 0.75
@ -133,9 +133,9 @@ namespace NeatCharts {
<g class="chart__gridLines" <g class="chart__gridLines"
fill="none" fill="none"
stroke="'.( $this->options['labelColor'] ).'" stroke="'.( $this->options['labelColor'] ).'"
stroke-opacity="0.4"
stroke-width="1" stroke-width="1"
vector-effect="non-scaling-stroke" vector-effect="non-scaling-stroke"
stroke-dasharray="2, 2"
shape-rendering="crispEdges"> shape-rendering="crispEdges">
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" /> <path class="chart__gridLinePaths" d="'.( $gridLines ).'" />
</g> </g>