Skip to content

Commit

Permalink
URLs now keep foreground/background and alpha!
Browse files Browse the repository at this point in the history
Try: http://hslpicker.com/#d829ff,0.56/#07f,0.55

Lots of refactoring:
- Backbones views are split up in seperate modules
- Concerns are better separated
- New site module manages site style and urls
- Reduced global polution
  • Loading branch information
imathis committed Mar 14, 2013
1 parent 5021a37 commit 3a2e967
Show file tree
Hide file tree
Showing 13 changed files with 4,884 additions and 1,393 deletions.
4 changes: 2 additions & 2 deletions Guardfile
Expand Up @@ -11,10 +11,10 @@ end
guard :shell do
watch /^assets\/javascripts\/.+\.(js|coffee)/ do |change|
file = "javascripts/hslpicker.js"
env = 'production'
env = 'dev'

lib = ['underscore.js', 'backbone.js', 'dragdealer.js'].collect {|item| Dir.glob("assets/javascripts/lib/#{item}") }.flatten.uniq
modules = ['assets/javascripts/modules/hslpicker.coffee']
modules = Dir.glob('assets/javascripts/modules/*.*')
fingerprint = Digest::MD5.hexdigest((lib|modules).map! { |path| "#{File.mtime(path).to_i}" }.join+env)

if File.exists?(file) and File.open(file) {|f| f.readline} =~ /#{fingerprint}/
Expand Down
266 changes: 266 additions & 0 deletions assets/javascripts/modules/color.coffee
@@ -0,0 +1,266 @@
color = Backbone.Model.extend

defaults: {}

randomColor: ->
[_.random(0, 360), 100, 50, 1]

updateRgb: (rgba) ->
rgba or= @hslToRgb @hsla()
@set rgb: [rgba[0], rgba[1], rgba[2]]
rgba

updateHsl: (hsla)->
@set h: hsla[0], s: hsla[1], l: hsla[2]

updateHex: (rgba) ->
@set hex: @rgbToHex rgba or @rgba()

h: (h) ->
if @inRange 'h', h
unless @get('h') is h
@set h: h
@updateHex @updateRgb()
h
else false

s: (s) ->
if @inRange 's', s
unless @get('s') is s
@set s: s
@updateHex @updateRgb()
s
else false

l: (l) ->
if @inRange 'l', l
unless @get('l') is l
@set l: l
@updateHex @updateRgb()
l
else false

a: (a) ->
if @inRange 'a', a
unless @get('a') is a
@set a: a
@updateHex @updateRgb()
a
else false

# Set hsla or get its current value as an array or string
hsla: (hsla) ->
if hsla?
hsla = @isHsl(hsla)
if hsla
if @hsla().join(',') isnt hsla.join(',')
@updateHex @updateRgb(@hslToRgb hsla)
@updateHsl hsla
@set a: if hsla[3]? then hsla[3] else 1
hsla
else
false
else
[@get('h'), @get('s'), @get('l'), @get('a')]

hslaStr: (hsla) ->
hsla or= @hsla()
"hsla(#{hsla[0]}, #{hsla[1]}%, #{hsla[2]}%, #{hsla[3]})"

rgba: (rgba) ->
if rgba?
rgba = @isRgb(rgba)
if rgba
if rgba.join(',') isnt @rgba().join(',')
@set rgb: [rgba[0], rgba[1], rgba[2]], a: if rgba[3]? then rgba[3] else 1
@updateHex(rgba)
@updateHsl(@rgbToHsl rgba)
rgba
else
false
else
@get('rgb').concat @get('a')

rgbaStr: ->
rgb = @get('rgb')
"rgba(#{rgb[0]}, #{rgb[1]}, #{rgb[2]}, #{@get('a')})"

hex: (hex) ->
if hex?
hex = @isHex(hex)
if hex
if @hex() isnt hex
@set hex: hex
rgba = @hexToRgb hex
@updateRgb rgba
@set a: rgba[3] or 1
@updateHsl(@rgbToHsl rgba)
hex
else
false
else
@get 'hex'

isHex: (hex, marker = true) ->
match = hex.match(/^#?([0-9a-fA-F]{3})([0-9a-fA-F]{3})?$/)?.slice(1)
return false unless match?

color = _.compact(match).join('')
if marker then '#'+color else color

isRgb: (rgb) ->
if typeof rgb is 'string'
match = rgb.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,?\s*(0?\.?\d+)?\s*\)$/)?.slice(1)
return false unless match?
rgb = (parseFloat c for c in _.compact(match))
rgb[3] = 1 unless rgb[3]? # If there isn't an alpha value already
valid = rgb[0] <= 255 and rgb[1] <= 255 and rgb[2] <= 255 and rgb[3] <= 1
if valid then rgb else false

isHsl: (hsl) ->
if typeof hsl is 'string'
match = hsl.match(/hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\%\s*,\s*(\d{1,3})\%\s*,?\s*(0?\.?\d+)?\s*\)$/)?.slice(1)
return false unless match?
hsl = (parseFloat c for c in _.compact(match))
hsl[3] = 1 unless hsl[3]? # If there isn't an alpha value already
valid = hsl[0] <= 360 and hsl[1] <= 100 and hsl[2] <= 100 and hsl[3] <= 1
if valid then hsl else false

valid: (color) ->
type = @type color
if type is 'hex' then @isHex(color)
else if type is 'rgb' then @isRgb(color)
else if type is 'hsl' then @isHsl(color)
else false

inRange: (part, val) ->
switch part
when 'h' then valid = val >= 0 and val <= 360
when 's','l' then valid = val >= 0 and val <= 100
when 'a' then valid = val >= 0 and val <= 1
valid

type: (color) ->
str = color.toString()
type =
if str.indexOf('#') >= 0 or str.length is 3 or str.length is 6
'hex'
else if str.indexOf('%')
'hsl'
else
'rgb'

hexToRgb: (hex) ->
hex = @isHex hex, false
return false unless hex

hex = ("#{c}#{c}" for c in hex).join('') if hex.length isnt 6 # expand the short hex by doubling each character, fc0 -> ffcc00
color = hex.match(/#?(.{2})(.{2})(.{2})/).slice(1)
color = (parseInt(c, 16) for c in color).concat [1]

hexToHsl: (hex) ->
hex = @isHex hex if hex.indexOf('#') >= 0 or hex.length < 6
return false unless hex
@rgbToHsl @hexToRgb(hex)

rgbToHex: (rgb) ->
rgb = @isRgb rgb if typeof rgb is 'string'
if rgb
hex = (parseFloat(c).toString(16) for c in rgb.slice(0,3))
hex = for c in hex
if c.length is 1 then "0#{c}" else c
hex = hex.join('')
if _.compact((i[0] is i[1] for i in hex.match(/.{1,2}/g))).length is 3
"##{hex[0]}#{hex[2]}#{hex[4]}"
else
"##{hex}"

rgbToHsl: (rgb) ->
rgb = @isRgb rgb if typeof rgb is 'string'
return false unless rgb

r = parseFloat(rgb[0]) / 255
g = parseFloat(rgb[1]) / 255
b = parseFloat(rgb[2]) / 255

max = Math.max(r, g, b)
min = Math.min(r, g, b)
diff = max - min
add = max + min

hue =
if min is max
0
else if r is max
((60 * (g - b) / diff) + 360) % 360
else if g is max
(60 * (b - r) / diff) + 120
else
(60 * (r - g) / diff) + 240

lum = 0.5 * add

sat =
if lum is 0
0
else if lum is 1
1
else if lum <= 0.5
diff / add
else
diff / (2 - add)

h = Math.round hue
s = Math.round sat*100
l = Math.round lum*100
a = parseFloat(rgb[3]) or 1

[h,s,l,a]


hslToRgb: (hsl) ->
if typeof hsl is 'string'
hsl = @isHsl hsl
return false unless hsl

hue = parseInt(hsl[0]) / 360
sat = parseInt(hsl[1]) / 100
lum = parseInt(hsl[2]) / 100

q = if lum <= .5
lum * (1 + sat)
else
lum + sat - (lum * sat)

p = 2 * lum - q

rt = hue + (1/3)
gt = hue
bt = hue - (1/3)

r = Math.round @hueToRgb(p, q, rt) * 255
g = Math.round @hueToRgb(p, q, gt) * 255
b = Math.round @hueToRgb(p, q, bt) * 255
a = parseFloat(hsl[3]) or 1

[r,g,b,a]

hslToHex: (hsl) ->
hsl = @isHsl hsl if typeof hsl is 'string'
return false unless hsl
@rgbToHex @hslToRgb(hsl)

hueToRgb: (p, q, h) ->
h += 1 if h < 0
h -= 1 if h > 1

if (h * 6) < 1
p + (q - p) * h * 6
else if (h * 2) < 1
q
else if (h * 3) < 2
p + (q - p) * ((2 / 3) - h) * 6
else
p

module.exports = (options) -> new color(options)

0 comments on commit 3a2e967

Please sign in to comment.