5 * @copyright 2012-2018 Leaf Corcoran
7 * @license http://opensource.org/licenses/MIT MIT
9 * @link http://leafo.github.io/scssphp
12 namespace Leafo\ScssPhp\Node
;
14 use Leafo\ScssPhp\Compiler
;
15 use Leafo\ScssPhp\Node
;
16 use Leafo\ScssPhp\Type
;
19 * Dimension + optional units
22 * This is a work-in-progress.
24 * The \ArrayAccess interface is temporary until the migration is complete.
27 * @author Anthon Pang <anthon.pang@gmail.com>
29 class Number
extends Node
implements \ArrayAccess
34 static public $precision = 10;
37 * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/
41 static protected $unitTable = [
54 'rad' => 6.28318530717958647692528676, // 2 * M_PI
85 * @param mixed $dimension
86 * @param mixed $initialUnit
88 public function __construct($dimension, $initialUnit)
90 $this->type
= Type
::T_NUMBER
;
91 $this->dimension
= $dimension;
92 $this->units
= is_array($initialUnit)
94 : ($initialUnit ?
[$initialUnit => 1]
99 * Coerce number to target units
101 * @param array $units
103 * @return \Leafo\ScssPhp\Node\Number
105 public function coerce($units)
107 if ($this->unitless()) {
108 return new Number($this->dimension
, $units);
111 $dimension = $this->dimension
;
113 foreach (static::$unitTable['in'] as $unit => $conv) {
114 $from = isset($this->units
[$unit]) ?
$this->units
[$unit] : 0;
115 $to = isset($units[$unit]) ?
$units[$unit] : 0;
116 $factor = pow($conv, $from - $to);
117 $dimension /= $factor;
120 return new Number($dimension, $units);
126 * @return \Leafo\ScssPhp\Node\Number
128 public function normalize()
130 $dimension = $this->dimension
;
133 $this->normalizeUnits($dimension, $units, 'in');
135 return new Number($dimension, $units);
141 public function offsetExists($offset)
143 if ($offset === -3) {
144 return $this->sourceColumn
!== null;
147 if ($offset === -2) {
148 return $this->sourceLine
!== null;
165 public function offsetGet($offset)
169 return $this->sourceColumn
;
172 return $this->sourceLine
;
175 return $this->sourceIndex
;
181 return $this->dimension
;
191 public function offsetSet($offset, $value)
194 $this->dimension
= $value;
195 } elseif ($offset === 2) {
196 $this->units
= $value;
197 } elseif ($offset == -1) {
198 $this->sourceIndex
= $value;
199 } elseif ($offset == -2) {
200 $this->sourceLine
= $value;
201 } elseif ($offset == -3) {
202 $this->sourceColumn
= $value;
209 public function offsetUnset($offset)
212 $this->dimension
= null;
213 } elseif ($offset === 2) {
215 } elseif ($offset === -1) {
216 $this->sourceIndex
= null;
217 } elseif ($offset === -2) {
218 $this->sourceLine
= null;
219 } elseif ($offset === -3) {
220 $this->sourceColumn
= null;
225 * Returns true if the number is unitless
229 public function unitless()
231 return ! array_sum($this->units
);
235 * Returns unit(s) as the product of numerator units divided by the product of denominator units
239 public function unitStr()
244 foreach ($this->units
as $unit => $unitSize) {
246 $numerators = array_pad($numerators, count($numerators) +
$unitSize, $unit);
251 $denominators = array_pad($denominators, count($denominators) +
$unitSize, $unit);
256 return implode('*', $numerators) . (count($denominators) ?
'/' . implode('*', $denominators) : '');
262 * @param \Leafo\ScssPhp\Compiler $compiler
266 public function output(Compiler
$compiler = null)
268 $dimension = round($this->dimension
, static::$precision);
270 $units = array_filter($this->units
, function ($unitSize) {
274 if (count($units) > 1 && array_sum($units) === 0) {
275 $dimension = $this->dimension
;
278 $this->normalizeUnits($dimension, $units, 'in');
280 $dimension = round($dimension, static::$precision);
281 $units = array_filter($units, function ($unitSize) {
286 $unitSize = array_sum($units);
288 if ($compiler && ($unitSize > 1 ||
$unitSize < 0 ||
count($units) > 1)) {
289 $compiler->throwError((string) $dimension . $this->unitStr() . " isn't a valid CSS value.");
294 $dimension = number_format($dimension, static::$precision, '.', '');
296 return (static::$precision ?
rtrim(rtrim($dimension, '0'), '.') : $dimension) . $unit;
302 public function __toString()
304 return $this->output();
310 * @param integer|float $dimension
311 * @param array $units
312 * @param string $baseUnit
314 private function normalizeUnits(&$dimension, &$units, $baseUnit = 'in')
316 $dimension = $this->dimension
;
319 foreach ($this->units
as $unit => $exp) {
320 if (isset(static::$unitTable[$baseUnit][$unit])) {
321 $factor = pow(static::$unitTable[$baseUnit][$unit], $exp);
324 $dimension /= $factor;
327 $units[$unit] = $exp +
(isset($units[$unit]) ?
$units[$unit] : 0);