summaryrefslogtreecommitdiff
path: root/public/assets/javascripts/ui/editor/LightControl.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/assets/javascripts/ui/editor/LightControl.js')
-rw-r--r--public/assets/javascripts/ui/editor/LightControl.js299
1 files changed, 264 insertions, 35 deletions
diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js
index c3e80c2..bd09dc2 100644
--- a/public/assets/javascripts/ui/editor/LightControl.js
+++ b/public/assets/javascripts/ui/editor/LightControl.js
@@ -1,43 +1,272 @@
var LightControl = View.extend({
- el: ".lightcontrol",
-
- events: {
- "mousedown": "stopPropagation",
- },
+ el: ".lightcontrol",
+
+ events: {
+ "mousedown": "stopPropagation",
+ "click .swatch": "clickSwatch",
+ "click label": "clickLabel",
+ "input #shadow-control": "updateShadow",
+ "mousedown #brightness-control": "beginBrightness",
+ "input #brightness-control": "updateBrightness",
+ "input #outline-hue": "updateShadow",
+ "input #wall-hue": "updateShadow",
+ },
+
+ initialize: function(){
+ this.colorPicker = new LabColorPicker(this, 180, 180)
+ this.$el.prepend( this.colorPicker.canvas )
+
+ this.$swatches = this.$(".swatch")
+ this.$labels = this.$(".swatch + label")
+ this.$swatch = {
+ wall: this.$("#wall-color"),
+ outline: this.$("#outline-color"),
+ floor: this.$("#floor-color"),
+ ceiling: this.$("#ceiling-color"),
+ }
+ this.$brightnessControl = this.$("#brightness-control")
+ },
- toggle: function(state){
+ modes: [ "wall", "outline", "floor", "ceiling" ],
+
+ load: function(data){
+ this.modes.forEach(function(mode){
+ Walls.setColor[mode](data[mode])
+ this.$swatch[ mode ].css("background-color", rgb_string(data[mode]))
+ }.bind(this))
+ this.setMode("wall")
+ },
+
+ loadDefaults: function(){
+ var colors = {
+ wall: app.defaults.wallColor.slice(),
+ outline: app.defaults.outlineColor.slice(),
+ floor: app.defaults.floorColor.slice(),
+ ceiling: app.defaults.ceilingColor.slice(),
+ }
+ this.load(colors)
+ },
+
+ toggle: function(state){
this.$el.toggleClass("active", state);
+ },
+
+ show: function(){
+ this.toggle(true)
+ },
+
+ hide: function(){
+ this.toggle(false)
+ },
+
+ pick: function(rgb, Lab){
+ this.labColor = Lab
+ this.setSwatchColor(this.mode, rgb)
+ Walls.setColor[ this.mode ](rgb)
+ },
+
+ setSwatchColor: function(mode, rgb) {
+ this.$swatch[ mode ].css("background-color", rgb_string(rgb))
+ },
+
+ initialState: null,
+
+ begin: function(){
+ this.initialState = this.serialize()
+ },
+
+ serialize: function(){
+ return {
+ mode: this.mode,
+ rgb: Walls.colors[ this.mode ]
+ }
+ },
+
+ finalize: function(){
+ if (! this.initialState) { return }
+ UndoStack.push({
+ type: 'update-colors',
+ undo: this.initialState,
+ redo: this.serialize(),
+ })
+ this.initialState = null
+ },
+
+ setMode: function (mode) {
+ var color, brightness
+ this.mode = mode
+ this.$swatches.removeClass("selected")
+ this.$labels.removeClass("selected")
+ this.$swatch[ mode ].addClass("selected")
+ color = Walls.colors[ mode ]
+
+ this.$(".swatch.selected").next("label").addClass("selected")
+ this.labColor = this.colorPicker.load(color)
+ this.$brightnessControl.val( this.labColor[0] )
+ },
+
+ clickLabel: function(e){
+ $(e.currentTarget).prev(".swatch").trigger("click")
+ },
+ clickSwatch: function(e){
+ var mode = $(e.currentTarget).data('mode')
+ this.setMode(mode)
+ },
+
+ beginBrightness: function(){
+ this.begin()
+ $(window).one("mouseup", this.finalize.bind(this))
+ },
+
+ updateBrightness: function(){
+ this.labColor[0] = parseFloat( this.$brightnessControl.val() )
+ var rgb = this.colorPicker.setLab( this.labColor )
+ this.pick(rgb, this.labColor)
+ },
- // toggle the class that makes the cursor a paintbucket
- // $("body").removeClass("pastePaper");
- },
- show: function(){
- this.toggle(true)
- },
- hide: function(){
- this.toggle(false)
- },
+})
-/*
- $("#shadow-control").on({
- mousedown: function(){ app.dragging = true },
- change: function(){
- var hex = (~~($(this).int() / 100 * 0xff)).toString(10)
- if (hex.length == 1) hex = "0" + hex;
- var color = "rgba(" + [hex, hex, hex, "1.0"] + ")"
- $(".face").css("border-color", color)
- }
- })
+var LabColorPicker = function (parent, w, h) {
+ var base = this
+ var canvas = this.canvas = document.createElement('canvas')
+ var ctx = this.ctx = canvas.getContext('2d')
+ var imageData = ctx.createImageData(w,h)
+ var data = imageData.data
- $("#brightness-control").on({
- mousedown: function(){ app.dragging = true },
- change: function(){
- var hex = (~~($(this).int() / 100 * 0xff)).toString(10)
- var color = "rgba(" + [hex, hex, hex, "0.9"] + ")"
- $("body,.face").css("background-color", color)
- }
- })
-*/
+// var cursor = this.cursor = document.createElement("div")
+// cursor.className = "colorPickerCursor"
-})
+ canvas.width = w
+ canvas.height = h
+ canvas.className = "colorPicker"
+
+ var ww = w-1
+ var hh = h-1
+
+ var L_range = [0, 110]
+ var a_range = [-86.185, 98.254]
+ var b_range = [-107.863, 94.482]
+
+ var rgb = [0,0,0]
+
+ var val = 80
+
+ this.mouse = new mouse({
+ el: canvas,
+ down: function(e, cursor){
+ parent.begin()
+ cursor.x.a = -cursor.x.a
+ base.pick(cursor.x.a, cursor.y.a)
+ },
+ drag: function(e, cursor){
+ cursor.x.b = -cursor.x.b
+ base.pick(cursor.x.b, cursor.y.b)
+ },
+ up: function(){
+ parent.finalize()
+ }
+ })
+
+ this.setLab = function(Lab) {
+ val = Lab[0]
+ this.paint()
+ var rgb = xyz2rgb(hunterlab2xyz(Lab[0], Lab[1], Lab[2])).map(Math.round)
+ return rgb
+ }
+ this.pick = function(i, j){
+ var x = mix( i/ww, a_range[0], a_range[1] )
+ var y = mix( j/hh, b_range[0], b_range[1] )
+ var rgb = xyz2rgb(hunterlab2xyz(val, x, y)).map(Math.round)
+ parent.pick( rgb, [val,x,y] )
+ }
+ this.load = function(rgba){
+ var Lab = xyz2hunterlab(rgb2xyz(rgba))
+ var val = clamp( Lab[0], L_range[0], L_range[1] )
+ var x = mix( norm(Lab[1], a_range[0], a_range[1]), 0, ww )
+ var y = mix( norm(Lab[2], b_range[0], b_range[1]), 0, hh )
+ // move the cursor
+ this.setLab(Lab)
+ return Lab
+ }
+ this.paint = function() {
+ val = clamp(val, L_range[0], L_range[1])
+ var x, y, t
+ for (var i = 0; i < w; i++) {
+ for (var j = 0; j < h; j++) {
+ x = mix( i/ww, a_range[0], a_range[1] )
+ y = mix( j/hh, b_range[0], b_range[1] )
+ t = (j*w + i) * 4
+ rgb = xyz2rgb(hunterlab2xyz(val, x, y))
+ data[t] = Math.round( rgb[0] )
+ data[t+1] = Math.round( rgb[1] )
+ data[t+2] = Math.round( rgb[2] )
+ data[t+3] = 255
+ }
+ }
+ ctx.putImageData(imageData,0,0)
+ }
+
+ function hunterlab2xyz (L,a,b) {
+ var_Y = L / 10
+ var_X = a / 17.5 * L / 10
+ var_Z = b / 7 * L / 10
+
+ Y = Math.pow(var_Y, 2)
+ X = ( var_X + Y ) / 1.02
+ Z = -( var_Z - Y ) / 0.847
+ xyz = [X,Y,Z]
+ }
+ function xyz2rgb(){
+ var var_X = xyz[0] / 100 //X from 0 to 95.047 (Observer = 2°, Illuminant = D65)
+ var var_Y = xyz[1] / 100 //Y from 0 to 100.000
+ var var_Z = xyz[2] / 100 //Z from 0 to 108.883
+
+ var_R = var_X * 3.2406 + var_Y * -1.5372 + var_Z * -0.4986
+ var_G = var_X * -0.9689 + var_Y * 1.8758 + var_Z * 0.0415
+ var_B = var_X * 0.0557 + var_Y * -0.2040 + var_Z * 1.0570
+
+ if ( var_R > 0.0031308 ) var_R = 1.055 * Math.pow( var_R, 1 / 2.4 ) - 0.055
+ else var_R = 12.92 * var_R
+ if ( var_G > 0.0031308 ) var_G = 1.055 * Math.pow( var_G, 1 / 2.4 ) - 0.055
+ else var_G = 12.92 * var_G
+ if ( var_B > 0.0031308 ) var_B = 1.055 * Math.pow( var_B, 1 / 2.4 ) - 0.055
+ else var_B = 12.92 * var_B
+
+ rgb[0] = clamp(var_R * 255, 0, 255)
+ rgb[1] = clamp(var_G * 255, 0, 255)
+ rgb[2] = clamp(var_B * 255, 0, 255)
+ return rgb
+ }
+ function rgb2xyz(RGB){
+ var var_R = ( RGB[0] / 255 ) // R from 0 to 255
+ var var_G = ( RGB[1] / 255 ) // G from 0 to 255
+ var var_B = ( RGB[2] / 255 ) // B from 0 to 255
+
+ if ( var_R > 0.04045 ) var_R = ( ( var_R + 0.055 ) / 1.055 ) ^ 2.4
+ else var_R = var_R / 12.92
+ if ( var_G > 0.04045 ) var_G = ( ( var_G + 0.055 ) / 1.055 ) ^ 2.4
+ else var_G = var_G / 12.92
+ if ( var_B > 0.04045 ) var_B = ( ( var_B + 0.055 ) / 1.055 ) ^ 2.4
+ else var_B = var_B / 12.92
+
+ var_R = var_R * 100
+ var_G = var_G * 100
+ var_B = var_B * 100
+
+ //Observer. = 2°, Illuminant = D65
+ var x = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805
+ var y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722
+ var z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505
+ return [x,y,z]
+ }
+ function xyz2hunterlab (XYZ) {
+ var X = XYZ[0]
+ var Y = XYZ[1] || 1e-6 // otherwise divide-by-zero error when converting rgb(0,0,0)
+ var Z = XYZ[2]
+ var L = 10 * sqrt( Y )
+ var a = 17.5 * ( ( ( 1.02 * X ) - Y ) / sqrt( Y ) )
+ var b = 7 * ( ( Y - ( 0.847 * Z ) ) / sqrt( Y ) )
+ return [L,a,b]
+ }
+}