mirror of
https://github.com/seigler/neat-charts
synced 2025-07-27 01:16:09 +00:00
Added BAR CHARTS!
This commit is contained in:
parent
603666e167
commit
c5f6c0476e
5 changed files with 116 additions and 23 deletions
22
README.md
22
README.md
|
@ -3,7 +3,11 @@
|
|||
PHP project to generate clean-looking SVG price charts
|
||||
|
||||

|
||||
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 
|
||||
|
||||
More examples at [cryptohistory.org](http://cryptohistory.org/).
|
||||
|
||||
## Requirements
|
||||
|
||||
|
@ -66,6 +70,7 @@ In your HTML:
|
|||
|
||||
## Available Options
|
||||
|
||||
### LineChart
|
||||
| Option | Default |
|
||||
| --- | --- |
|
||||
| width | 800 |
|
||||
|
@ -77,6 +82,21 @@ In your HTML:
|
|||
| fontSize | 15 |
|
||||
| yAxisEnabled | true |
|
||||
| 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
|
||||
|
||||
|
|
29
demo.php
29
demo.php
|
@ -1,11 +1,11 @@
|
|||
<?php
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
function randomData($count = 96) {
|
||||
function randomData($count = 96, $offsetMax = 100) {
|
||||
$randomData = [];
|
||||
$offset = 100 * (rand()/getRandMax())**2;
|
||||
$scale = max(0.1 * $offset, 100 * rand() / getRandMax());
|
||||
$volatility = 0.25 * (rand()/getRandMax())**3 + 0.25;
|
||||
$offset = $offsetMax * (rand()/getRandMax())**2;
|
||||
$scale = max(0.25 * $offset, 100 * rand() / getRandMax());
|
||||
$volatility = 0.5 * (rand()/getRandMax())**3 + 0.25;
|
||||
for ($n = 0, $current = $offset + 0.5 * $scale; $n < $count; $n++) {
|
||||
$current -= $offset;
|
||||
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
||||
|
@ -39,7 +39,7 @@ function randomData($count = 96) {
|
|||
</figure>
|
||||
</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>
|
||||
<?php
|
||||
$chart = new NeatCharts\LineChart(randomData(), [
|
||||
|
@ -49,7 +49,8 @@ $chart = new NeatCharts\LineChart(randomData(), [
|
|||
'labelColor'=>'#222',
|
||||
'smoothed'=>false,
|
||||
'fontSize'=>14,
|
||||
'yAxisZero'=>true
|
||||
'yAxisZero'=>true,
|
||||
'filled'=>true
|
||||
]);
|
||||
echo $chart->render();
|
||||
?>
|
||||
|
@ -61,8 +62,8 @@ echo $chart->render();
|
|||
<figure>
|
||||
<?php
|
||||
$chart = new NeatCharts\LineChart(randomData(12), [
|
||||
'width'=>300,
|
||||
'height'=>300,
|
||||
'width'=>400,
|
||||
'height'=>300, // null works as a height too, it picks a height that makes the plot look good
|
||||
'lineColor'=>'#080',
|
||||
'labelColor'=>'#222',
|
||||
'smoothed'=>true,
|
||||
|
@ -88,6 +89,18 @@ $chart = new NeatCharts\LineChart(randomData(48), [
|
|||
'xAxisEnabled'=>false
|
||||
]);
|
||||
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>
|
||||
</figure>
|
||||
|
|
59
src/NeatCharts/BarChart.php
Normal file
59
src/NeatCharts/BarChart.php
Normal 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>';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,8 @@ namespace NeatCharts {
|
|||
'fontSize' => 15,
|
||||
'yAxisEnabled'=>true,
|
||||
'xAxisEnabled'=>false,
|
||||
'yAxisZero'=>false
|
||||
'yAxisZero'=>false,
|
||||
'filled'=>false
|
||||
];
|
||||
parent::setOptions($options);
|
||||
}
|
||||
|
@ -128,7 +129,7 @@ namespace NeatCharts {
|
|||
stroke="url(#neatchart-fadeFromNothing-'.( $chartID ).')"
|
||||
marker-end="url(#neatchart-markerCircle-'.( $chartID ).')"
|
||||
>
|
||||
<path d="'.( $chartPoints ).'" />'.($this->options['yAxisZero'] ? '
|
||||
<path d="'.( $chartPoints ).'" />'.($this->options['filled'] ? '
|
||||
<path
|
||||
stroke="none"
|
||||
fill="url(#neatchart-fadeFromNothing-'.( $chartID ).')"
|
||||
|
|
|
@ -91,20 +91,20 @@ namespace NeatCharts {
|
|||
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
|
||||
$labelPrecision = $this->getPrecision($labelInterval);
|
||||
|
||||
$this->padding['left'] = $this->options['fontSize'] * 0.6 * (
|
||||
1 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval)
|
||||
) + 10;
|
||||
$this->padding['left'] = $this->options['fontSize'] * 0.65 * (
|
||||
2.5 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval)
|
||||
);
|
||||
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
||||
|
||||
// Top and bottom grid lines
|
||||
$gridLines =
|
||||
'M10,0 '.$this->width.',0 '.
|
||||
' M10,'.$this->height.','.$this->width.','.$this->height;
|
||||
'M0,0 '.$this->width.',0 '.
|
||||
' M0,'.$this->height.','.$this->width.','.$this->height;
|
||||
|
||||
// Top and bottom grid labels
|
||||
$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->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->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>';
|
||||
|
||||
// Main labels and grid lines
|
||||
for (
|
||||
|
@ -117,8 +117,8 @@ namespace NeatCharts {
|
|||
$labelHeight < $this->height - 1.5 * $this->options['fontSize'] &&
|
||||
$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>';
|
||||
$gridLines .= ' M0,'.$labelHeight.' '.$this->width.','.$labelHeight;
|
||||
$gridText .= '<text text-anchor="end" x="-'.($this->options['fontSize']).'" y="'.($labelHeight + $this->options['fontSize'] * 0.4).'">'.$this->labelFormat($labelY, $labelPrecision).'</text>';
|
||||
$gridLines .= ' M-'.($this->options['fontSize'] * 0.65).','.$labelHeight.' '.$this->width.','.$labelHeight;
|
||||
} else if ( // label is too close
|
||||
$labelHeight < $this->height - $this->options['fontSize'] * 0.75 &&
|
||||
$labelHeight > $this->options['fontSize'] * 0.75
|
||||
|
@ -133,9 +133,9 @@ namespace NeatCharts {
|
|||
<g class="chart__gridLines"
|
||||
fill="none"
|
||||
stroke="'.( $this->options['labelColor'] ).'"
|
||||
stroke-opacity="0.4"
|
||||
stroke-width="1"
|
||||
vector-effect="non-scaling-stroke"
|
||||
stroke-dasharray="2, 2"
|
||||
shape-rendering="crispEdges">
|
||||
<path class="chart__gridLinePaths" d="'.( $gridLines ).'" />
|
||||
</g>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue