mirror of
https://github.com/seigler/neat-charts
synced 2025-07-27 09:26:10 +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
|
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
|
## 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
|
||||||
|
|
||||||
|
|
29
demo.php
29
demo.php
|
@ -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,7 +39,7 @@ 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(), [
|
||||||
|
@ -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();
|
||||||
?>
|
?>
|
||||||
|
@ -61,8 +62,8 @@ echo $chart->render();
|
||||||
<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>
|
||||||
|
|
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,
|
'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 ).')"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue