class Sass::Script::Value::Color
the cached RGB and HSL values are retained.
If only the alpha channel is modified using {#with},
It’s always stored, as 1 if nothing else is specified.
The alpha channel of a color is independent of its RGB or HSL representation.
that component is calculated and cached.
for example, {#red} for an HSL color –
Once a property is accessed that requires the other representation –
and if it’s created with HSL values, it’s represented as HSLA.
if it’s created with RGB values, it’s represented as RGBA,
It’s originally represented as whatever its input is;
A color may be represented internally as RGBA, HSLA, or both.
A SassScript object representing a CSS color.
def self.from_hex(hex_string, alpha = nil)
-
(Color)
-
def self.from_hex(hex_string, alpha = nil) unless hex_string =~ /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})?$/i || hex_string =~ /^#?([0-9a-f])([0-9a-f])([0-9a-f])([0-9a-f])?$/i raise ArgumentError.new("#{hex_string.inspect} is not a valid hex color.") end red = $1.ljust(2, $1).to_i(16) green = $2.ljust(2, $2).to_i(16) blue = $3.ljust(2, $3).to_i(16) alpha = $4.ljust(2, $4).to_i(16).to_f / 0xff if $4 hex_string = "##{hex_string}" unless hex_string[0] == ?# attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string} attrs[:alpha] = alpha if alpha new(attrs) end
def self.int_to_rgba(color)
-
(Array
- Array of 4 numbers representing r,g,b and alpha)
Parameters:
-
color
(Integer
) --
Other tags:
- Private: -
def self.int_to_rgba(color) rgba = (0..3).map {|n| color >> (n << 3) & 0xff}.reverse rgba[-1] = rgba[-1] / 255.0 rgba end
def alpha
-
(Integer)
-
def alpha @attrs[:alpha].to_f end
def alpha?
-
(Boolean)
-
def alpha? alpha < 1 end
def blue
-
(Integer)
-
def blue hsl_to_rgb! @attrs[:blue] end
def div(other)
-
(Sass::SyntaxError)
- if `other` is a number with units
Returns:
-
(Color)
- The resulting color
Parameters:
-
other
(Value
) -- The right-hand side of the operator
def div(other) if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color) piecewise(other, :/) else super end end
def eq(other)
-
(Bool)
- True if this value is the same as the other,
Parameters:
-
other
(Value
) -- The right-hand side of the operator
def eq(other) Sass::Script::Value::Bool.new( other.is_a?(Color) && rgb == other.rgb && alpha == other.alpha) end
def green
-
(Integer)
-
def green hsl_to_rgb! @attrs[:green] end
def hash
def hash [rgb, alpha].hash end
def hex_str
def hex_str red, green, blue = rgb.map {|num| num.to_s(16).rjust(2, '0')} "##{red}#{green}#{blue}" end
def hsl
-
(Array
- A frozen three-element array of the)
def hsl [hue, saturation, lightness].freeze end
def hsl_to_rgb!
def hsl_to_rgb! return if @attrs[:red] && @attrs[:blue] && @attrs[:green] h = @attrs[:hue] / 360.0 s = @attrs[:saturation] / 100.0 l = @attrs[:lightness] / 100.0 # Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color. m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s m1 = l * 2 - m2 @attrs[:red], @attrs[:green], @attrs[:blue] = [ hue_to_rgb(m1, m2, h + 1.0 / 3), hue_to_rgb(m1, m2, h), hue_to_rgb(m1, m2, h - 1.0 / 3) ].map {|c| Sass::Util.round(c * 0xff)} end
def hsla
-
(Array
- A frozen four-element array of the hue,)
def hsla [hue, saturation, lightness, alpha].freeze end
def hue
-
(Numeric)
-
def hue rgb_to_hsl! @attrs[:hue] end
def hue_to_rgb(m1, m2, h)
def hue_to_rgb(m1, m2, h) h += 1 if h < 0 h -= 1 if h > 1 return m1 + (m2 - m1) * h * 6 if h * 6 < 1 return m2 if h * 2 < 1 return m1 + (m2 - m1) * (2.0 / 3 - h) * 6 if h * 3 < 2 m1 end
def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)
-
(ArgumentError)
- if not enough attributes are specified -
(ArgumentError)
- if not enough attributes are specified, -
(Sass::SyntaxError)
- if any color value isn't in the specified range
Parameters:
-
representation
(String
) -- The original representation of the color -
rgba
(Array
) -- A three- or four-element array -
attrs
({Symbol => Numeric}
) -- A hash of color attributes to values
Overloads:
-
initialize(rgba, [representation])
-
initialize(attrs)
def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false) super(nil) if attrs.is_a?(Array) unless (3..4).include?(attrs.size) raise ArgumentError.new("Color.new(array) expects a three- or four-element array") end red, green, blue = attrs[0...3].map {|c| Sass::Util.round(c)} @attrs = {:red => red, :green => green, :blue => blue} @attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1 @representation = representation else attrs = attrs.reject {|_k, v| v.nil?} hsl = [:hue, :saturation, :lightness] & attrs.keys rgb = [:red, :green, :blue] & attrs.keys if !allow_both_rgb_and_hsl && !hsl.empty? && !rgb.empty? raise ArgumentError.new("Color.new(hash) may not have both HSL and RGB keys specified") elsif hsl.empty? && rgb.empty? raise ArgumentError.new("Color.new(hash) must have either HSL or RGB keys specified") elsif !hsl.empty? && hsl.size != 3 raise ArgumentError.new("Color.new(hash) must have all three HSL values specified") elsif !rgb.empty? && rgb.size != 3 raise ArgumentError.new("Color.new(hash) must have all three RGB values specified") end @attrs = attrs @attrs[:hue] %= 360 if @attrs[:hue] @attrs[:alpha] ||= 1 @representation = @attrs.delete(:representation) end [:red, :green, :blue].each do |k| next if @attrs[k].nil? @attrs[k] = Sass::Util.restrict(Sass::Util.round(@attrs[k]), 0..255) end [:saturation, :lightness].each do |k| next if @attrs[k].nil? @attrs[k] = Sass::Util.restrict(@attrs[k], 0..100) end @attrs[:alpha] = Sass::Util.restrict(@attrs[:alpha], 0..1) end
def inspect
-
(String)
- The hex value
def inspect alpha? ? rgba_str : hex_str end
def lightness
-
(Numeric)
-
def lightness rgb_to_hsl! @attrs[:lightness] end
def minus(other)
-
(Sass::SyntaxError)
- if `other` is a number with units
Returns:
-
(Color)
- The resulting color
Parameters:
-
other
(Value
) -- The right-hand side of the operator
def minus(other) if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color) piecewise(other, :-) else super end end
def mod(other)
-
(Sass::SyntaxError)
- if `other` is a number with units
Returns:
-
(Color)
- The resulting color
Parameters:
-
other
(Number, Color
) -- The right-hand side of the operator
def mod(other) if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color) piecewise(other, :%) else raise NoMethodError.new(nil, :mod) end end
def name
-
(String, nil)
-
def name COLOR_NAMES_REVERSE[rgba] end
def operation_name(operation)
def operation_name(operation) case operation when :+ "add" when :- "subtract" when :* "multiply" when :/ "divide" when :% "modulo" end end
def piecewise(other, operation)
def piecewise(other, operation) other_num = other.is_a? Number if other_num && !other.unitless? raise Sass::SyntaxError.new( "Cannot #{operation_name(operation)} a number with units (#{other}) to a color (#{self})." ) end result = [] (0...3).each do |i| res = rgb[i].to_f.send(operation, other_num ? other.value : other.rgb[i]) result[i] = [[res, 255].min, 0].max end if !other_num && other.alpha != alpha raise Sass::SyntaxError.new("Alpha channels must be equal: #{self} #{operation} #{other}") end with(:red => result[0], :green => result[1], :blue => result[2]) end
def plus(other)
-
(Sass::SyntaxError)
- if `other` is a number with units
Returns:
-
(Color)
- The resulting color
Parameters:
-
other
(Value
) -- The right-hand side of the operator
def plus(other) if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color) piecewise(other, :+) else super end end
def red
-
(Integer)
-
def red hsl_to_rgb! @attrs[:red] end
def rgb
-
(Array
- A frozen three-element array of the red, green, and blue)
def rgb [red, green, blue].freeze end
def rgb_to_hsl!
def rgb_to_hsl! return if @attrs[:hue] && @attrs[:saturation] && @attrs[:lightness] r, g, b = [:red, :green, :blue].map {|k| @attrs[k] / 255.0} # Algorithm from http://en.wikipedia.org/wiki/HSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV max = [r, g, b].max min = [r, g, b].min d = max - min h = case max when min; 0 when r; 60 * (g - b) / d when g; 60 * (b - r) / d + 120 when b; 60 * (r - g) / d + 240 end l = (max + min) / 2.0 s = if max == min 0 elsif l < 0.5 d / (2 * l) else d / (2 - 2 * l) end @attrs[:hue] = h % 360 @attrs[:saturation] = s * 100 @attrs[:lightness] = l * 100 end
def rgba
-
(Array
- A frozen four-element array of the red, green,)
def rgba [red, green, blue, alpha].freeze end
def rgba_str
def rgba_str split = options[:style] == :compressed ? ',' : ', ' "rgba(#{rgb.join(split)}#{split}#{Number.round(alpha)})" end
def saturation
-
(Numeric)
-
def saturation rgb_to_hsl! @attrs[:saturation] end
def smallest
def smallest small_explicit_str = alpha? ? rgba_str : hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3') [representation, COLOR_NAMES_REVERSE[rgba], small_explicit_str]. compact.min_by {|str| str.size} end
def times(other)
-
(Sass::SyntaxError)
- if `other` is a number with units
Returns:
-
(Color)
- The resulting color
Parameters:
-
other
(Number, Color
) -- The right-hand side of the operator
def times(other) if other.is_a?(Sass::Script::Value::Number) || other.is_a?(Sass::Script::Value::Color) piecewise(other, :*) else raise NoMethodError.new(nil, :times) end end
def to_s(opts = {})
-
(String)
- The string representation
def to_s(opts = {}) return smallest if options[:style] == :compressed return representation if representation # IE10 doesn't properly support the color name "transparent", so we emit # generated transparent colors as rgba(0, 0, 0, 0) in favor of that. See # #1782. return rgba_str if Number.basically_equal?(alpha, 0) return name if name alpha? ? rgba_str : hex_str end
def with(attrs)
-
(ArgumentError)
- if both RGB and HSL keys are specified
Returns:
-
(Color)
- The new Color object
Parameters:
-
attrs
({Symbol => Numeric}
) --
def with(attrs) attrs = attrs.reject {|_k, v| v.nil?} hsl = !([:hue, :saturation, :lightness] & attrs.keys).empty? rgb = !([:red, :green, :blue] & attrs.keys).empty? if hsl && rgb raise ArgumentError.new("Cannot specify HSL and RGB values for a color at the same time") end if hsl [:hue, :saturation, :lightness].each {|k| attrs[k] ||= send(k)} elsif rgb [:red, :green, :blue].each {|k| attrs[k] ||= send(k)} else # If we're just changing the alpha channel, # keep all the HSL/RGB stuff we've calculated attrs = @attrs.merge(attrs) end attrs[:alpha] ||= alpha Color.new(attrs, nil, :allow_both_rgb_and_hsl) end