Add hsl().

This commit is contained in:
Natalie Weizenbaum 2016-09-21 10:01:17 -07:00 committed by Natalie Weizenbaum
parent 84d1339043
commit 30df7507c8
2 changed files with 131 additions and 4 deletions

View File

@ -12,6 +12,7 @@ void defineCoreFunctions(Environment environment) {
environment.setFunction(
new BuiltInCallable("rgb", r"$red, $green, $blue", (arguments) {
// TODO: support calc strings
var red = arguments[0].assertNumber("red");
var green = arguments[1].assertNumber("green");
var blue = arguments[2].assertNumber("blue");
@ -103,6 +104,18 @@ void defineCoreFunctions(Environment environment) {
color1.alpha * weightScale + color2.alpha * (1 - weightScale));
}));
// ## HSL
environment.setFunction(
new BuiltInCallable("hsl", r"$hue, $saturation, $lightness", (arguments) {
// TODO: support calc strings
var hue = arguments[0].assertNumber("hue");
var saturation = arguments[1].assertNumber("saturation");
var lightness = arguments[2].assertNumber("lightness");
return new SassColor.hsl(hue.value, saturation.value, lightness.value);
}));
// ## Introspection
environment.setFunction(new BuiltInCallable("inspect", r"$value",

View File

@ -2,6 +2,8 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:math' as math;
import '../exception.dart';
import '../utils.dart';
import '../visitor/interface/value.dart';
@ -10,18 +12,63 @@ import '../value.dart';
// TODO(nweiz): track original representation.
// TODO(nweiz): support an alpha channel.
class SassColor extends Value {
final int red;
final int green;
final int blue;
int get red {
if (_red == null) _hslToRgb();
return _red;
}
int _red;
int get green {
if (_green == null) _hslToRgb();
return _green;
}
int _green;
int get blue {
if (_blue == null) _hslToRgb();
return _blue;
}
int _blue;
num get hue {
if (_hue == null) _rgbToHsl();
return _hue;
}
num _hue;
num get saturation {
if (_saturation == null) _rgbToHsl();
return _saturation;
}
num _saturation;
num get lightness {
if (_lightness == null) _rgbToHsl();
return _lightness;
}
num _lightness;
final num alpha;
SassColor.rgb(this.red, this.green, this.blue, [double alpha])
SassColor.rgb(this._red, this._green, this._blue, [double alpha])
: alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha") {
RangeError.checkValueInInterval(red, 0, 255, "red");
RangeError.checkValueInInterval(green, 0, 255, "green");
RangeError.checkValueInInterval(blue, 0, 255, "blue");
}
SassColor.hsl(num hue, num saturation, num lightness, [double alpha])
: _hue = hue % 360,
_saturation = fuzzyAssertRange(saturation, 0, 100, "saturation"),
_lightness = fuzzyAssertRange(lightness, 0, 100, "lightness"),
alpha = alpha == null ? 1 : fuzzyAssertRange(alpha, 0, 1, "alpha");
/*=T*/ accept/*<T>*/(ValueVisitor/*<T>*/ visitor) => visitor.visitColor(this);
SassColor assertColor([String name]) => this;
@ -57,4 +104,71 @@ class SassColor extends Value {
other.blue == blue;
int get hashCode => red.hashCode ^ green.hashCode ^ blue.hashCode;
void _rgbToHsl() {
// Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
var scaledRed = red / 255;
var scaledGreen = green / 255;
var scaledBlue = blue / 255;
var max = math.max(math.max(scaledRed, scaledGreen), scaledBlue);
var min = math.min(math.min(scaledRed, scaledGreen), scaledBlue);
var delta = max - min;
if (max == min) {
_hue = 0;
} else if (max == scaledRed) {
_hue = (60 * (scaledGreen - scaledBlue) / delta) % 360;
} else if (max == scaledGreen) {
_hue = (120 + 60 * (scaledBlue - scaledRed) / delta) % 360;
} else if (max == scaledBlue) {
_hue = (240 + 60 * (scaledRed - scaledGreen) / delta) % 360;
}
_lightness = 50 * (max + min);
if (max == min) {
_saturation = 0;
} else if (_lightness < 0.5) {
_saturation = 5000 * delta / _lightness;
} else {
_saturation = 5000 * delta / (100 - _lightness);
}
}
void _hslToRgb() {
// Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
var scaledHue = hue / 360;
var scaledSaturation = saturation / 100;
var scaledLightness = lightness / 100;
var m2 = scaledLightness <= 0.5
? scaledLightness * (scaledSaturation + 1)
: scaledLightness +
scaledSaturation -
scaledLightness * scaledSaturation;
var m1 = scaledLightness * 2 - m2;
_red = _hueToRgb(m1, m2, scaledHue + 1 / 3);
_green = _hueToRgb(m1, m2, scaledHue);
_blue = _hueToRgb(m1, m2, scaledHue - 1 / 3);
}
int _hueToRgb(num m1, num m2, num hue) {
// Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
if (hue < 0) hue += 1;
if (hue > 1) hue -= 1;
num result;
if (hue < 1 / 6) {
result = m1 + (m2 - m1) * hue * 6;
} else if (hue < 1 / 2) {
result = m2;
} else if (hue < 2 / 3) {
result = m1 + (m2 - m1) * (2 / 3 - hue) * 6;
} else {
result = m1;
}
return (result * 255).round();
}
}