added options for sparklines

This commit is contained in:
Joshua Seigler 2016-07-02 01:02:57 -04:00
parent f43540f785
commit 5d73afddd0
3 changed files with 91 additions and 63 deletions

View file

@ -1,5 +1,20 @@
<?php
require_once 'vendor/autoload.php';
function randomData($count = 96) {
$randomData = [];
$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 < $count; $n++) {
$current -= $offset;
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
$current += $offset;
$randomData[$n] = $current;
}
return $randomData;
}
?>
<!DOCTYPE html>
<html lang="en-US">
@ -27,18 +42,7 @@ require_once 'vendor/autoload.php';
<h2>SVG chart in <code>svg</code> tag</h2>
<figure>
<?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;
}
$chart = new NeatCharts\LineChart($chartData, [
$chart = new NeatCharts\LineChart(randomData(), [
'width'=>800,
'height'=>250,
'lineColor'=>'#F00',
@ -47,6 +51,24 @@ $chart = new NeatCharts\LineChart($chartData, [
'fontSize'=>14
]);
echo $chart->render();
?>
<figcaption>Random generated data, loaded right in the page</figcaption>
</figure>
</section>
<section>
<h2>SVG sparkline in <code>svg</code> tag</h2>
<figure>
<?php
$chart = new NeatCharts\LineChart(randomData(48), [
'width'=>100,
'height'=>20,
'lineColor'=>'#000',
'smoothed'=>false,
'fontSize'=>2,
'yAxisEnabled'=>false,
'xAxisEnabled'=>false
]);
echo $chart->render();
?>
<figcaption>Random generated data, loaded right in the page</figcaption>
</figure>

View file

@ -85,22 +85,59 @@ namespace NeatCharts {
$this->options['height'] = $this->height + $this->padding['top'] + $this->padding['bottom'];
}
$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) {
$labelModulation /= 2.5;
} else {
$labelModulation /= 2;
}
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
$labelPrecision = $this->getPrecision($labelInterval);
if ($this->options['yAxisEnabled']) {
$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) {
$labelModulation /= 2.5;
} else {
$labelModulation /= 2;
}
$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->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
$this->padding['left'] = $this->options['fontSize'] * 0.6 * (
1 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval)
) + 10;
$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;
// 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>';
// Main labels and grid lines
for (
$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 = $this->transformY($labelY);
if ( // label is not too close to the min or max
$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;
} else if ( // label is too close
$labelHeight < $this->height - $this->options['fontSize'] * 0.75 &&
$labelHeight > $this->options['fontSize'] * 0.75
) {
$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;
}
}
} else {
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
}
$chartPoints = 'M';
$chartSplines = 'M'.
@ -126,39 +163,6 @@ namespace NeatCharts {
}
}
// Top and bottom grid lines
$gridLines =
'M10,0 '.$this->width.',0 '.
' M10,'.$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>';
// Main labels and grid lines
for (
$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 = $this->transformY($labelY);
if ( // label is not too close to the min or max
$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;
} else if ( // label is too close
$labelHeight < $this->height - $this->options['fontSize'] * 0.75 &&
$labelHeight > $this->options['fontSize'] * 0.75
) {
$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;
}
}
$chartID = rand();
$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">
<defs>

View file

@ -7,7 +7,9 @@ namespace NeatCharts {
'lineColor' => '#000',
'labelColor' => '#000',
'smoothed' => false,
'fontSize' => 15
'fontSize' => 15,
'yAxisEnabled'=>true,
'xAxisEnabled'=>false
];
protected $width;
@ -66,8 +68,8 @@ namespace NeatCharts {
}
public abstract function setData($chartData);
public function render($inline = false) {
return ($inline ? '' : '<?xml version="1.0" standalone="no"?>') . $this->output;
public function render() {
return $this->output;
}
}
}