diff --git a/src/NeatCharts/LineChart.php b/src/NeatCharts/LineChart.php index 3033c1e..adb1cbc 100644 --- a/src/NeatCharts/LineChart.php +++ b/src/NeatCharts/LineChart.php @@ -78,67 +78,11 @@ namespace NeatCharts { http://vis4.net/blog/posts/doing-the-line-charts-right/ */ $aspectRatio = max(0.25, min(0.75, 1 / $averageAbsSlope)); - $this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right']; - if (isset($this->options['height'])) { - $this->height = $this->options['height'] - $this->padding['top'] - $this->padding['bottom']; - } else { - $this->height = floor($aspectRatio * $this->width); - $this->options['height'] = $this->height + $this->padding['top'] + $this->padding['bottom']; + if (!isset($this->options['height'])) { + $this->options['height'] = floor($aspectRatio * $this->options['width']); } - $this->padding['left'] = $this->padding['right'] = $this->options['fontSize'] / 2; - 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']; - - // Top and bottom grid lines - $gridLines = - 'M10,0 '.$this->width.',0 '. - ' M10,'.$this->height.','.$this->width.','.$this->height; - - // Top and bottom grid labels - $gridText = - ''.($this->labelFormat($this->yMax, $labelPrecision + 1)).'' . - ''.($this->labelFormat($this->yMin, $labelPrecision + 1)).''; - - // 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 .= ''.$this->labelFormat($labelY, $labelPrecision).''; - $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']; - } + $gridLabelsXML = parent::buildGridLabelXML(); $chartPoints = 'M'; if ($this->options['smoothed']) { @@ -163,6 +107,7 @@ namespace NeatCharts { } $chartID = rand(); + $this->output = ' @@ -174,22 +119,7 @@ namespace NeatCharts { - '.( $this->options['yAxisEnabled'] || $this->options['xAxisEnabled'] ? ' - - - - - '.( $gridText ).' - ' : '').' + '.( $this->options['yAxisEnabled'] || $this->options['xAxisEnabled'] ? $gridLabelsXML : '').' yRange = $this->yMax - $this->yMin; } + protected function buildGridLabelXML() { + $this->width = $this->options['width'] - $this->padding['left'] - $this->padding['right']; + $this->height = $this->options['height'] - $this->padding['top'] - $this->padding['bottom']; + if ($this->options['yAxisEnabled'] || $this->options['xAxisEnabled']) { + $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']; + + // Top and bottom grid lines + $gridLines = + 'M10,0 '.$this->width.',0 '. + ' M10,'.$this->height.','.$this->width.','.$this->height; + + // Top and bottom grid labels + $gridText = + ''.($this->labelFormat($this->yMax, $labelPrecision + 1)).'' . + ''.($this->labelFormat($this->yMin, $labelPrecision + 1)).''; + + // 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 .= ''.$this->labelFormat($labelY, $labelPrecision).''; + $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; + } + } + + return ' + + + + + '.( $gridText ).' + '; + } else { + return ''; + } + } + final public function __construct($chartData, $options = []) { $this->setOptions($options); $this->setData($chartData); @@ -82,7 +157,7 @@ namespace NeatCharts { public function setOptions($options) { $this->options = array_replace($this->options, $options); - $this->padding['left'] = $this->options['fontSize'] * 5; + $this->padding['left'] = $this->padding['right'] = $this->options['fontSize'] / 2; $this->padding['top'] = $this->padding['bottom'] = $this->options['fontSize']; }