mirror of
https://github.com/seigler/neat-charts
synced 2025-07-27 09:26:10 +00:00
feat: add background fill, begin work on x-axis
This commit is contained in:
parent
eb9a5e9279
commit
d59dd86f14
6 changed files with 54 additions and 35 deletions
|
@ -1,18 +1,23 @@
|
||||||
<?php
|
<?php
|
||||||
require_once 'vendor/autoload.php';
|
require_once 'vendor/autoload.php';
|
||||||
|
|
||||||
$chartData = [];
|
function randomData($count = 20, $offsetMax = 100) {
|
||||||
$offset = 100 * (rand()/getRandMax())**4;
|
$randomData = [];
|
||||||
$scale = 100 * (rand()/getRandMax())**2;
|
$duration = 60 * 5 + rand() * 60 * 60 * 24;
|
||||||
$volatility = 0.5 * (rand()/getRandMax())**3;
|
$begin = time() - $duration;
|
||||||
for ($n = 0, $current = $offset + 0.5 * $scale; $n < 24; $n++) {
|
$offset = $offsetMax * (rand()/getRandMax())**2;
|
||||||
$current -= $offset;
|
$scale = max(0.25 * $offset, 100 * rand() / getRandMax());
|
||||||
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
$volatility = 0.25 * (rand()/getRandMax())**3 + 0.25;
|
||||||
$current += $offset;
|
for ($n = 0, $current = $offset + 0.5 * $scale; $n < $count; $n++) {
|
||||||
$chartData[$n] = $current;
|
$current -= $offset;
|
||||||
|
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
||||||
|
$current += $offset;
|
||||||
|
$randomData[$begin + $duration / $count * $n] = $current;
|
||||||
|
}
|
||||||
|
return $randomData;
|
||||||
}
|
}
|
||||||
|
|
||||||
$chart = new NeatCharts\LineChart($chartData, [
|
$chart = new NeatCharts\LineChart(randomData(), [
|
||||||
'width'=>500,
|
'width'=>500,
|
||||||
'height'=>400,
|
'height'=>400,
|
||||||
'lineColor'=>'#00F',
|
'lineColor'=>'#00F',
|
||||||
|
|
10
demo.php
10
demo.php
|
@ -1,8 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
require_once 'vendor/autoload.php';
|
require_once 'vendor/autoload.php';
|
||||||
|
|
||||||
function randomData($count = 96, $offsetMax = 100) {
|
function randomData($count = 96, $offsetMax = 2000) {
|
||||||
$randomData = [];
|
$randomData = [];
|
||||||
|
$duration = 60 * 5 + rand() * 60 * 60 * 24;
|
||||||
|
$begin = time() - $duration;
|
||||||
$offset = $offsetMax * (rand()/getRandMax())**2;
|
$offset = $offsetMax * (rand()/getRandMax())**2;
|
||||||
$scale = max(0.25 * $offset, 100 * rand() / getRandMax());
|
$scale = max(0.25 * $offset, 100 * rand() / getRandMax());
|
||||||
$volatility = 0.5 * (rand()/getRandMax())**3 + 0.25;
|
$volatility = 0.5 * (rand()/getRandMax())**3 + 0.25;
|
||||||
|
@ -10,7 +12,7 @@ function randomData($count = 96, $offsetMax = 100) {
|
||||||
$current -= $offset;
|
$current -= $offset;
|
||||||
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
$current *= 1 + $volatility * (rand()/getRandMax() - 0.5);
|
||||||
$current += $offset;
|
$current += $offset;
|
||||||
$randomData[$n] = $current;
|
$randomData[$begin + $duration / $count * $n] = $current;
|
||||||
}
|
}
|
||||||
return $randomData;
|
return $randomData;
|
||||||
}
|
}
|
||||||
|
@ -39,7 +41,7 @@ function randomData($count = 96, $offsetMax = 100) {
|
||||||
</figure>
|
</figure>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>Line chart in <code>svg</code> tag, zero axis shown, filled</h2>
|
<h2>Line chart in <code>svg</code> tag, zero axis shown, filled, smoothed</h2>
|
||||||
<figure>
|
<figure>
|
||||||
<?php
|
<?php
|
||||||
$chart = new NeatCharts\LineChart(randomData(), [
|
$chart = new NeatCharts\LineChart(randomData(), [
|
||||||
|
@ -47,7 +49,7 @@ $chart = new NeatCharts\LineChart(randomData(), [
|
||||||
'height'=>250,
|
'height'=>250,
|
||||||
'lineColor'=>'#F00',
|
'lineColor'=>'#F00',
|
||||||
'labelColor'=>'#222',
|
'labelColor'=>'#222',
|
||||||
'smoothed'=>false,
|
'smoothed'=>true,
|
||||||
'fontSize'=>14,
|
'fontSize'=>14,
|
||||||
'yAxisZero'=>true,
|
'yAxisZero'=>true,
|
||||||
'filled'=>true
|
'filled'=>true
|
||||||
|
|
|
@ -9,9 +9,10 @@ namespace NeatCharts {
|
||||||
'markerColor' => '#000',
|
'markerColor' => '#000',
|
||||||
'labelColor' => '#000',
|
'labelColor' => '#000',
|
||||||
'fontSize' => 15,
|
'fontSize' => 15,
|
||||||
'yAxisEnabled'=>true,
|
'yAxisEnabled' => true,
|
||||||
'xAxisEnabled'=>false,
|
'xAxisEnabled' => false,
|
||||||
'yAxisZero'=>true
|
'yAxisZero' => true,
|
||||||
|
'background' => 'none'
|
||||||
];
|
];
|
||||||
parent::setOptions($options);
|
parent::setOptions($options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,10 @@ namespace NeatCharts {
|
||||||
'markerColor' => '#000',
|
'markerColor' => '#000',
|
||||||
'labelColor' => '#000',
|
'labelColor' => '#000',
|
||||||
'fontSize' => 15,
|
'fontSize' => 15,
|
||||||
'yAxisEnabled'=>true,
|
'yAxisEnabled' => true,
|
||||||
'xAxisEnabled'=>false,
|
'xAxisEnabled' => false,
|
||||||
'yAxisZero'=>false
|
'yAxisZero' => false,
|
||||||
|
'background' => 'none'
|
||||||
];
|
];
|
||||||
parent::setOptions($options);
|
parent::setOptions($options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,11 @@ namespace NeatCharts {
|
||||||
'labelColor' => '#000',
|
'labelColor' => '#000',
|
||||||
'smoothed' => false,
|
'smoothed' => false,
|
||||||
'fontSize' => 15,
|
'fontSize' => 15,
|
||||||
'yAxisEnabled'=>true,
|
'yAxisEnabled' => true,
|
||||||
'xAxisEnabled'=>false,
|
'xAxisEnabled' => false,
|
||||||
'yAxisZero'=>false,
|
'yAxisZero' => false,
|
||||||
'filled'=>false
|
'filled' => false,
|
||||||
|
'background' => 'none'
|
||||||
];
|
];
|
||||||
parent::setOptions($options);
|
parent::setOptions($options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,10 @@ namespace NeatCharts {
|
||||||
'labelColor' => '#000',
|
'labelColor' => '#000',
|
||||||
'smoothed' => false,
|
'smoothed' => false,
|
||||||
'fontSize' => 15,
|
'fontSize' => 15,
|
||||||
'yAxisEnabled'=>true,
|
'yAxisEnabled' => true,
|
||||||
'xAxisEnabled'=>false,
|
'xAxisEnabled' => true,
|
||||||
'yAxisZero'=>false
|
'yAxisZero' => false,
|
||||||
|
'background' => 'none'
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $width;
|
protected $width;
|
||||||
|
@ -24,6 +25,7 @@ namespace NeatCharts {
|
||||||
protected $yMax;
|
protected $yMax;
|
||||||
protected $yRange;
|
protected $yRange;
|
||||||
protected $padding = ['top'=>10, 'right'=>10, 'bottom'=>10, 'left'=>10];
|
protected $padding = ['top'=>10, 'right'=>10, 'bottom'=>10, 'left'=>10];
|
||||||
|
protected $timeIntervals = [ 5 * 60, 60 * 60, 24 * 60 * 60, 28 * 60 * 60 ]; // 5 min, 1 hr, 24 hr, 1 month
|
||||||
|
|
||||||
protected function labelFormat($float, $places, $minPlaces = 0) {
|
protected function labelFormat($float, $places, $minPlaces = 0) {
|
||||||
$value = number_format($float, max($minPlaces, $places));
|
$value = number_format($float, max($minPlaces, $places));
|
||||||
|
@ -31,7 +33,6 @@ namespace NeatCharts {
|
||||||
return (strpos($value, '.') === false ? $value . '.' : $value);
|
return (strpos($value, '.') === false ? $value . '.' : $value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transform data coords to chart coords */
|
|
||||||
/* Transform data coords to chart coords */
|
/* Transform data coords to chart coords */
|
||||||
protected function transformX($x) {
|
protected function transformX($x) {
|
||||||
return round(
|
return round(
|
||||||
|
@ -49,7 +50,7 @@ namespace NeatCharts {
|
||||||
if (!is_numeric($value)) { return false; }
|
if (!is_numeric($value)) { return false; }
|
||||||
$decimal = $value - floor($value); //get the decimal portion of the number
|
$decimal = $value - floor($value); //get the decimal portion of the number
|
||||||
if ($decimal == 0) { return 0; } //if it's a whole number
|
if ($decimal == 0) { return 0; } //if it's a whole number
|
||||||
$precision = strlen(trim(number_format($decimal,10),'0')) - 1; //-2 to account for '0.'
|
$precision = strlen(trim(number_format($decimal,10),'0')) - 1; //-1 to account for '0.'
|
||||||
return $precision;
|
return $precision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,21 +79,23 @@ namespace NeatCharts {
|
||||||
protected function buildGridLabelXML() {
|
protected function buildGridLabelXML() {
|
||||||
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
||||||
$this->height = $this->options['height'] - $this->padding['top'] - $this->padding['bottom'];
|
$this->height = $this->options['height'] - $this->padding['top'] - $this->padding['bottom'];
|
||||||
if ($this->options['yAxisEnabled'] || $this->options['xAxisEnabled']) {
|
if ($this->options['yAxisEnabled']) {
|
||||||
$numLabels = 2 + ceil($this->height / $this->options['fontSize'] / 6);
|
$numLabels = 4 + ceil($this->height / $this->options['fontSize'] / 4);
|
||||||
$labelInterval = $this->yRange / $numLabels;
|
$labelInterval = $this->yRange / $numLabels;
|
||||||
$labelModulation = 10 ** (1 + floor(-log($this->yRange / $numLabels, 10)));
|
$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
|
// 1 here is a fudge factor so we get multiples of 2.5 more often
|
||||||
if (fmod($labelInterval * $labelModulation, 2.5) < fmod($labelInterval * $labelModulation, 2) + 0.1) {
|
if (fmod($labelInterval * $labelModulation, 2.5) < fmod($labelInterval * $labelModulation, 2) + 1) {
|
||||||
$labelModulation /= 2.5;
|
$labelModulation /= 2.5;
|
||||||
} else {
|
} else {
|
||||||
$labelModulation /= 2;
|
$labelModulation /= 2;
|
||||||
}
|
}
|
||||||
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
|
$labelInterval = ceil($labelInterval * $labelModulation) / $labelModulation;
|
||||||
$labelPrecision = $this->getPrecision($labelInterval);
|
$labelPrecision = $this->getPrecision($labelInterval);
|
||||||
|
$digitsLeft = max(1, ceil(log($this->yMax, 10)));
|
||||||
|
$commas = max(0, floor(($digitsLeft - 1) / 3));
|
||||||
|
|
||||||
$this->padding['left'] = $this->options['fontSize'] * 0.65 * (
|
$this->padding['left'] = $this->options['fontSize'] * 0.65 * (
|
||||||
2.5 + max(1, ceil(log($this->yMax, 10))) + $this->getPrecision($labelInterval)
|
2.5 + $digitsLeft + $commas + $this->getPrecision($labelInterval)
|
||||||
);
|
);
|
||||||
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
$this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right'];
|
||||||
|
|
||||||
|
@ -130,8 +133,14 @@ namespace NeatCharts {
|
||||||
}
|
}
|
||||||
|
|
||||||
return '
|
return '
|
||||||
|
<rect class="chart__background"
|
||||||
|
fill="'.( $this->options['background'] ).'"
|
||||||
|
x="-'.( $this->padding['left'] ).'"
|
||||||
|
y="-'.( $this->padding['top'] ).'"
|
||||||
|
width="'.( $this->options['width'] ).'"
|
||||||
|
height="'.( $this->options['height'] ).'"
|
||||||
|
/>
|
||||||
<g class="chart__gridLines"
|
<g class="chart__gridLines"
|
||||||
fill="none"
|
|
||||||
stroke="'.( $this->options['labelColor'] ).'"
|
stroke="'.( $this->options['labelColor'] ).'"
|
||||||
stroke-opacity="0.4"
|
stroke-opacity="0.4"
|
||||||
stroke-width="1"
|
stroke-width="1"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue