From 2bf7351025b29d1bc8ec2e5792dcb0532c4deb95 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 26 Aug 2014 18:59:24 -0400 Subject: color picker thingie --- .../assets/javascripts/ui/editor/LightControl.js | 262 +++++++++++++++++++-- 1 file changed, 238 insertions(+), 24 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index c3e80c2..b1c5b85 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -4,40 +4,254 @@ var LightControl = View.extend({ events: { "mousedown": "stopPropagation", + "click #wall-color": "editWallColor", + "click #outline-color": "editOutlineColor", + "click label": "clickLabel", + "input #shadow-control": "updateShadow", + "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.$wallSwatch = this.$("#wall-color") + this.$outlineSwatch = this.$("#outline-color") + this.$brightnessControl = this.$("#brightness-control") + + this.setMode("wall") + + this.setWallColor([255,255,255], false) + this.setOutlineColor([0,0,0]) + }, + toggle: function(state){ this.$el.toggleClass("active", state); - - // toggle the class that makes the cursor a paintbucket - // $("body").removeClass("pastePaper"); }, + show: function(){ this.toggle(true) }, + hide: function(){ this.toggle(false) }, + + pick: function(rgb, Lab){ + this.labColor = Lab + switch (this.mode) { + case "wall": + this.setWallColor(rgb) + break + case "outline": + this.setOutlineColor(rgb) + break + } + }, + + wallColor: [255,255,255], + outlineColor: [0,0,0], + + setMode: function (mode) { + var color, brightness + this.mode = mode + switch (mode) { + case "wall": + this.$wallSwatch.addClass("selected") + this.$outlineSwatch.removeClass("selected") + color = this.wallColor + break + case "outline": + this.$outlineSwatch.addClass("selected") + this.$wallSwatch.removeClass("selected") + color = this.outlineColor + break + } + this.labColor = this.colorPicker.load(color) + this.$brightnessControl.val( this.labColor[0] ) + }, + + clickLabel: function(e){ + $(e.currentTarget).prev(".swatch").trigger("click") + }, + editWallColor: function(){ + this.setMode("wall") + }, + editOutlineColor: function(){ + this.setMode("outline") + }, + + setWallColor: function(rgb, repaint){ + repaint = typeof repaint != "undefined" ? repaint : true + var rgbColor = rgb_string(rgb) + var rgbaColor = rgba_string(rgb, 0.95) + this.wallColor = rgb + this.$wallSwatch.css("background-color", rgbColor) + Rooms.walls.forEach(function(wall){ + wall.outline(rgbaColor, null) + }) + }, -/* - $("#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) - } - }) - - $("#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) - } - }) -*/ + setOutlineColor: function(rgb){ + repaint = typeof repaint != "undefined" ? repaint : true + var rgbColor = rgb_string(rgb) + this.outlineColor = rgb + this.$outlineSwatch.css("background-color", rgbColor) + Rooms.walls.forEach(function(wall){ + wall.outline(null, rgbColor) + }) + }, + + updateBrightness: function(){ + this.labColor[0] = parseFloat( this.$brightnessControl.val() ) + var rgb = this.colorPicker.setLab( this.labColor ) + this.pick(rgb, this.labColor) + }, }) + +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 + +// var cursor = this.cursor = document.createElement("div") +// cursor.className = "colorPickerCursor" + + canvas.width = w + canvas.height = h + canvas.className = "colorPicker" + + var down = false + + 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){ + 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) + } + }) + + 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] + 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] + } + + // this.paint(val) +} -- cgit v1.2.3-70-g09d2 From 36b90395b85d6859dd78af9eb71c3df343e24841 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Tue, 26 Aug 2014 19:10:56 -0400 Subject: catch divide-by-zero error in xyz2hunterlab function --- public/assets/javascripts/ui/editor/LightControl.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index b1c5b85..1bd660e 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -170,6 +170,7 @@ var LabColorPicker = function (parent, w, h) { var y = mix( norm(Lab[2], b_range[0], b_range[1]), 0, hh ) // move the cursor this.setLab(Lab) + console.log(rgba) return Lab } this.paint = function() { @@ -245,13 +246,11 @@ var LabColorPicker = function (parent, w, h) { } function xyz2hunterlab (XYZ) { var X = XYZ[0] - var Y = XYZ[1] + 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] } - - // this.paint(val) } -- cgit v1.2.3-70-g09d2 From 098a330fab261885a86c7ae9a5b2ed294987dc6b Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 27 Aug 2014 12:47:05 -0400 Subject: fix tests --- .../javascripts/rectangles/engine/rooms/builder.js | 4 +--- .../javascripts/rectangles/engine/rooms/grouper.js | 13 +++++++++---- public/assets/javascripts/rectangles/models/surface.js | 3 --- public/assets/javascripts/ui/editor/LightControl.js | 1 - views/partials/meta.ejs | 17 +++++++++++++++++ 5 files changed, 27 insertions(+), 11 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/rectangles/engine/rooms/builder.js b/public/assets/javascripts/rectangles/engine/rooms/builder.js index f321f71..5396ced 100644 --- a/public/assets/javascripts/rectangles/engine/rooms/builder.js +++ b/public/assets/javascripts/rectangles/engine/rooms/builder.js @@ -165,7 +165,6 @@ room.mx_ceiling.push(el) } }.bind(this)) - } else { // render floor and ceiling for the entire rectangle @@ -282,7 +281,6 @@ el.side = CEILING return el } - this.make_wall = function (klass) { var el = new MX.Object3D(".face" + (klass || "")) el.width = el.height = el.scaleX = el.scaleY = el.scaleZ = 1 @@ -293,7 +291,7 @@ el.side = 0 el.rect = null el.destroy = function(){ - this.el = this.rect = this.face = null + this.el = this.rect = this.face = null } // possible if walls are opaque diff --git a/public/assets/javascripts/rectangles/engine/rooms/grouper.js b/public/assets/javascripts/rectangles/engine/rooms/grouper.js index cde9fbb..2ec1ee7 100644 --- a/public/assets/javascripts/rectangles/engine/rooms/grouper.js +++ b/public/assets/javascripts/rectangles/engine/rooms/grouper.js @@ -83,7 +83,10 @@ collection.sort( useX ? sort.compare_zx : sort.compare_xz ) collection.forEach(function(mx){ - if (last_mx && last_mx.rect.eq(mx.rect)) { + if (mx.culled) { + return + } + if (last_mx && mx && last_mx.rect.eq(mx.rect)) { // culls half-walls if (last_mx.rect.id == mx.rect.id) { last_mx.height += mx.height/2 @@ -91,9 +94,11 @@ last_mx.face.y.b += mx.height/2 } last_mx.side = side - mx.culled = true - mx.destroy() - scene.remove(mx) + if (! mx.culled) { + scene.remove(mx) + mx.destroy() + mx.culled = true + } return } widthVec = mx.rect[useX ? 'x' : 'y'].clone() diff --git a/public/assets/javascripts/rectangles/models/surface.js b/public/assets/javascripts/rectangles/models/surface.js index 636f7c0..53977c8 100644 --- a/public/assets/javascripts/rectangles/models/surface.js +++ b/public/assets/javascripts/rectangles/models/surface.js @@ -147,9 +147,6 @@ Surface.prototype.index_for_x = function(x, min_i){ min_i = min_i || 0 - if (min_i >= this.faces.length-1) { - return -1 - } for (var i = min_i; i < this.faces.length; i++) { if (this.faces[i].x.contains(x)) { return i diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index 1bd660e..f35b19e 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -170,7 +170,6 @@ var LabColorPicker = function (parent, w, h) { var y = mix( norm(Lab[2], b_range[0], b_range[1]), 0, hh ) // move the cursor this.setLab(Lab) - console.log(rgba) return Lab } this.paint = function() { diff --git a/views/partials/meta.ejs b/views/partials/meta.ejs index ceaaba1..9916b34 100644 --- a/views/partials/meta.ejs +++ b/views/partials/meta.ejs @@ -1,3 +1,20 @@ + + + -- cgit v1.2.3-70-g09d2 From 63b0e94e3e36838240c2d86e780a641c2255ed89 Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Wed, 27 Aug 2014 13:03:46 -0400 Subject: floor/ceiling colors --- .../assets/javascripts/rectangles/models/room.js | 12 +++++ .../assets/javascripts/ui/editor/LightControl.js | 63 ++++++++++++++++++++-- public/assets/stylesheets/app.css | 9 +++- views/controls/editor/light-control.ejs | 7 ++- 4 files changed, 83 insertions(+), 8 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/rectangles/models/room.js b/public/assets/javascripts/rectangles/models/room.js index 33a94d0..1cc929f 100644 --- a/public/assets/javascripts/rectangles/models/room.js +++ b/public/assets/javascripts/rectangles/models/room.js @@ -182,6 +182,18 @@ return collision } + Room.prototype.setFloorColor = function(rgbColor) { + this.mx_floor.map(function(mx){ + mx.el.style.backgroundColor = rgbColor + }) + } + + Room.prototype.setCeilingColor = function(rgbColor) { + this.mx_ceiling.map(function(mx){ + mx.el.style.backgroundColor = rgbColor + }) + } + if ('window' in this) { window.Room = Room } diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index f35b19e..a3a19c7 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -6,6 +6,8 @@ var LightControl = View.extend({ "mousedown": "stopPropagation", "click #wall-color": "editWallColor", "click #outline-color": "editOutlineColor", + "click #floor-color": "editFloorColor", + "click #ceiling-color": "editCeilingColor", "click label": "clickLabel", "input #shadow-control": "updateShadow", "input #brightness-control": "updateBrightness", @@ -17,14 +19,20 @@ var LightControl = View.extend({ this.colorPicker = new LabColorPicker(this, 180, 180) this.$el.prepend( this.colorPicker.canvas ) + this.$swatches = this.$(".swatch") + this.$labels = this.$(".swatch + label") this.$wallSwatch = this.$("#wall-color") this.$outlineSwatch = this.$("#outline-color") + this.$floorSwatch = this.$("#floor-color") + this.$ceilingSwatch = this.$("#ceiling-color") this.$brightnessControl = this.$("#brightness-control") this.setMode("wall") - this.setWallColor([255,255,255], false) - this.setOutlineColor([0,0,0]) + this.setWallColor(this.wallColor, false) + this.setOutlineColor(this.outlineColor) + this.setFloorColor(this.floorColor) + this.setCeilingColor(this.ceilingColor) }, toggle: function(state){ @@ -48,27 +56,44 @@ var LightControl = View.extend({ case "outline": this.setOutlineColor(rgb) break + case "floor": + this.setFloorColor(rgb) + break + case "ceiling": + this.setCeilingColor(rgb) + break } }, wallColor: [255,255,255], outlineColor: [0,0,0], + floorColor: [246,246,246], + ceilingColor: [255,255,255], setMode: function (mode) { var color, brightness this.mode = mode + this.$swatches.removeClass("selected") + this.$labels.removeClass("selected") switch (mode) { case "wall": this.$wallSwatch.addClass("selected") - this.$outlineSwatch.removeClass("selected") color = this.wallColor break case "outline": this.$outlineSwatch.addClass("selected") - this.$wallSwatch.removeClass("selected") color = this.outlineColor break + case "floor": + this.$floorSwatch.addClass("selected") + color = this.floorColor + break + case "ceiling": + this.$ceilingSwatch.addClass("selected") + color = this.ceilingColor + break } + this.$(".swatch.selected").next("label").addClass("selected") this.labColor = this.colorPicker.load(color) this.$brightnessControl.val( this.labColor[0] ) }, @@ -83,7 +108,15 @@ var LightControl = View.extend({ this.setMode("outline") }, - setWallColor: function(rgb, repaint){ + editFloorColor: function(){ + this.setMode("floor") + }, + + editCeilingColor: function(){ + this.setMode("ceiling") + }, + + setWallColor: function(rgb, repaint){ repaint = typeof repaint != "undefined" ? repaint : true var rgbColor = rgb_string(rgb) var rgbaColor = rgba_string(rgb, 0.95) @@ -94,6 +127,26 @@ var LightControl = View.extend({ }) }, + setFloorColor: function(rgb, repaint){ + repaint = typeof repaint != "undefined" ? repaint : true + var rgbColor = rgb_string(rgb) + this.floorColor = rgb + this.$floorSwatch.css("background-color", rgbColor) + Rooms.forEach(function(room){ + room.setFloorColor(rgbColor) + }) + }, + + setCeilingColor: function(rgb, repaint){ + repaint = typeof repaint != "undefined" ? repaint : true + var rgbColor = rgb_string(rgb) + this.ceilingColor = rgb + this.$ceilingSwatch.css("background-color", rgbColor) + Rooms.forEach(function(room){ + room.setCeilingColor(rgbColor) + }) + }, + setOutlineColor: function(rgb){ repaint = typeof repaint != "undefined" ? repaint : true var rgbColor = rgb_string(rgb) diff --git a/public/assets/stylesheets/app.css b/public/assets/stylesheets/app.css index ff35ca4..6f6a192 100755 --- a/public/assets/stylesheets/app.css +++ b/public/assets/stylesheets/app.css @@ -1201,6 +1201,7 @@ input[type="range"]::-webkit-slider-thumb { height: 20px; border: 1px solid black; display: inline-block; + cursor: pointer; } .swatch.selected { border-width: 2px; @@ -1213,7 +1214,13 @@ input[type="range"]::-webkit-slider-thumb { font-weight: 300; position: relative; top: -6px; - margin-right: 15px; + padding-left: 5px; + display: inline-block; + width: 60px; + cursor: pointer; +} +.color-swatches label.selected { + font-weight: 500; } diff --git a/views/controls/editor/light-control.ejs b/views/controls/editor/light-control.ejs index 4324087..02a78b6 100644 --- a/views/controls/editor/light-control.ejs +++ b/views/controls/editor/light-control.ejs @@ -6,8 +6,11 @@
-
-
+
+
+
+
+
-- cgit v1.2.3-70-g09d2 From e35e2f338ee7b14d8396485e58cb5593060add8e Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Thu, 28 Aug 2014 17:55:31 -0400 Subject: persisting wall colors in db --- public/assets/javascripts/ui/editor/EditorSettings.js | 7 ++++--- public/assets/javascripts/ui/editor/LightControl.js | 16 ++++++++-------- server/lib/api/projects.js | 3 +++ server/lib/schemas/Project.js | 1 + 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/ui/editor/EditorSettings.js b/public/assets/javascripts/ui/editor/EditorSettings.js index 2d3201e..2a3929a 100644 --- a/public/assets/javascripts/ui/editor/EditorSettings.js +++ b/public/assets/javascripts/ui/editor/EditorSettings.js @@ -35,8 +35,8 @@ var EditorSettings = FormView.extend({ data.walls && Walls.deserialize(data.walls) data.startPosition && scene.camera.move(data.startPosition) - if (data.colors) { - this.parent.lightControl.load() + if (data.colors && data.colors.wall) { + this.parent.lightControl.load(data.colors) } else { this.parent.lightControl.loadDefaults() @@ -136,7 +136,8 @@ var EditorSettings = FormView.extend({ fd.append( "description", this.$description.val() ) fd.append( "privacy", this.$privacy.filter(":checked").val() == "private" ) fd.append( "rooms", JSON.stringify( Rooms.serialize() ) ) - fd.append( "walls", JSON.stringify( Rooms.serializeWalls() ) ) + fd.append( "walls", JSON.stringify( Walls.serialize() ) ) + fd.append( "colors", JSON.stringify( Walls.colors ) ) fd.append( "media", JSON.stringify( Scenery.serialize() ) ) fd.append( "startPosition", JSON.stringify( app.position(scene.camera) ) ) diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index 5133de2..84f2e58 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -29,19 +29,19 @@ var LightControl = View.extend({ }, load: function(data){ - this.setWallColor(data.wallColor, false) - this.setOutlineColor(data.outlineColor) - this.setFloorColor(data.floorColor) - this.setCeilingColor(data.ceilingColor) + this.setWallColor(data.wall, false) + this.setOutlineColor(data.outline) + this.setFloorColor(data.floor) + this.setCeilingColor(data.ceiling) this.setMode("wall") }, loadDefaults: function(){ var colors = { - wallColor: app.defaults.wallColor.slice(), - outlineColor: app.defaults.outlineColor.slice(), - floorColor: app.defaults.floorColor.slice(), - ceilingColor: app.defaults.ceilingColor.slice(), + wall: app.defaults.wallColor.slice(), + outline: app.defaults.outlineColor.slice(), + floor: app.defaults.floorColor.slice(), + ceiling: app.defaults.ceilingColor.slice(), } this.load(colors) }, diff --git a/server/lib/api/projects.js b/server/lib/api/projects.js index bd3cb81..2a5beff 100644 --- a/server/lib/api/projects.js +++ b/server/lib/api/projects.js @@ -39,6 +39,7 @@ var projects = { data.rooms = JSON.parse(data.rooms) data.walls = JSON.parse(data.walls) data.media = JSON.parse(data.media) + data.colors = JSON.parse(data.colors) data.startPosition = JSON.parse(data.startPosition) upload.put("projects", req.files.thumbnail, { @@ -91,8 +92,10 @@ var projects = { Project.findOne({ _id: _id }, function(err, doc){ if (err || ! doc) { return res.json({ error: err }) } _.extend(doc, data) + doc.rooms = JSON.parse(data.rooms) doc.walls = JSON.parse(data.walls) + doc.colors = JSON.parse(data.colors) doc.media = JSON.parse(data.media) doc.startPosition = JSON.parse(data.startPosition) diff --git a/server/lib/schemas/Project.js b/server/lib/schemas/Project.js index 0f54eaa..abf34fb 100644 --- a/server/lib/schemas/Project.js +++ b/server/lib/schemas/Project.js @@ -30,6 +30,7 @@ var ProjectSchema = new mongoose.Schema({ rooms: [mongoose.Schema.Types.Mixed], walls: [mongoose.Schema.Types.Mixed], media: [mongoose.Schema.Types.Mixed], + colors: mongoose.Schema.Types.Mixed, startPosition: mongoose.Schema.Types.Mixed, user_id: { type: mongoose.Schema.ObjectId, index: true }, created_at: { type: Date }, -- cgit v1.2.3-70-g09d2 From a7e198fd71b1d0b9ec544c3f2b1e38eaca4d719f Mon Sep 17 00:00:00 2001 From: Jules Laplace Date: Fri, 29 Aug 2014 22:13:20 -0400 Subject: undo/redo for colors --- .../javascripts/rectangles/engine/rooms/_walls.js | 37 ++- .../javascripts/rectangles/engine/scenery/undo.js | 75 +++--- .../assets/javascripts/rectangles/util/minotaur.js | 2 +- .../javascripts/rectangles/util/undostack.js | 13 +- .../assets/javascripts/ui/editor/LightControl.js | 268 +++++++++------------ views/controls/editor/light-control.ejs | 8 +- 6 files changed, 201 insertions(+), 202 deletions(-) (limited to 'public/assets/javascripts/ui/editor/LightControl.js') diff --git a/public/assets/javascripts/rectangles/engine/rooms/_walls.js b/public/assets/javascripts/rectangles/engine/rooms/_walls.js index 046961b..f2f395b 100644 --- a/public/assets/javascripts/rectangles/engine/rooms/_walls.js +++ b/public/assets/javascripts/rectangles/engine/rooms/_walls.js @@ -86,8 +86,43 @@ var wall = base.lookup[ wall_data.id ] wall.deserialize( wall_data ) }) + }, + + base.setColor = { + + wall: function(rgb){ + var rgbaColor = rgba_string(rgb, app.defaults.wallOpacity) + Walls.colors.wall = rgb + Walls.forEach(function(wall){ + wall.outline(rgbaColor, null) + }) + }, + + outline: function(rgb){ + var rgbColor = rgb_string(rgb) + Walls.colors.outline = rgb + Walls.forEach(function(wall){ + wall.outline(null, rgbColor) + }) + }, + + floor: function(rgb){ + var rgbColor = rgb_string(rgb) + Walls.colors.floor = rgb + Rooms.forEach(function(room){ + room.setFloorColor(rgbColor) + }) + }, + + ceiling: function(rgb){ + var rgbColor = rgb_string(rgb) + Walls.colors.ceiling = rgb + Rooms.forEach(function(room){ + room.setCeilingColor(rgbColor) + }) + }, + } - } if ('window' in this) { diff --git a/public/assets/javascripts/rectangles/engine/scenery/undo.js b/public/assets/javascripts/rectangles/engine/scenery/undo.js index 1632c5b..ac9fdc0 100644 --- a/public/assets/javascripts/rectangles/engine/scenery/undo.js +++ b/public/assets/javascripts/rectangles/engine/scenery/undo.js @@ -1,7 +1,7 @@ (function(){ - UndoStack.register([ - { - type: "create-scenery", + UndoStack.register([ + { + type: "create-scenery", undo: function(state){ Scenery.remove(state.id) @@ -14,9 +14,9 @@ // TODO: watch individual scenery object here Minotaur.watch( app.router.editorView.settings ) }, - }, - { - type: "update-scenery", + }, + { + type: "update-scenery", undo: function(state){ var scenery = Scenery.find(state.id) scenery.deserialize(state) @@ -43,9 +43,9 @@ // TODO: watch individual scenery object here Minotaur.watch( app.router.editorView.settings ) }, - }, - { - type: "destroy-scenery", + }, + { + type: "destroy-scenery", undo: function(state){ Scenery.deserialize([ state ]) @@ -58,12 +58,12 @@ // TODO: watch individual scenery object here Minotaur.watch( app.router.editorView.settings ) }, - }, - - // - - { - type: "create-room", + }, + + // + + { + type: "create-room", undo: function(room){ Rooms.remove(room) Rooms.clipper.update() @@ -71,52 +71,55 @@ redo: function(room){ Rooms.add(new Room(room)) Rooms.clipper.update() - app.tube("builder-pick-room", room) + app.tube("builder-pick-room", room) }, - }, - { - type: "update-room", + }, + { + type: "update-room", undo: function(state){ var room = Rooms.list[state.id] room.rect.assign( state.rect ) room.height = state.height Rooms.clipper.update() - app.tube("builder-pick-room", room) + app.tube("builder-pick-room", room) }, redo: function(state){ var room = Rooms.list[state.id] room.rect.assign( state.rect ) room.height = state.height Rooms.clipper.update() - app.tube("builder-pick-room", room) + app.tube("builder-pick-room", room) }, - }, - { - type: "destroy-room", + }, + { + type: "destroy-room", undo: function(room){ Rooms.add(new Room(room)) Rooms.clipper.update() - app.tube("builder-pick-room", room) + app.tube("builder-pick-room", room) }, redo: function(room){ Rooms.remove(room) Rooms.clipper.update() }, - }, - - // + }, + + // - { - type: "update-wallpaper", + { + type: "update-wallpaper", undo: function(state){ var wall = Walls.lookup[state.id] wall.deserialize(state) }, - redo: function(state){ - var wall = Walls.lookup[state.id] - wall.deserialize(state) + }, + { + type: "update-colors", + undo: function(state){ + Walls.setColor[ state.mode ]( state.rgb ) + app.router.editorView.lightControl.setSwatchColor( state.mode, state.rgb ) }, - }, - - ]) + }, + + ]) })() diff --git a/public/assets/javascripts/rectangles/util/minotaur.js b/public/assets/javascripts/rectangles/util/minotaur.js index 039a053..e6a37e0 100644 --- a/public/assets/javascripts/rectangles/util/minotaur.js +++ b/public/assets/javascripts/rectangles/util/minotaur.js @@ -4,7 +4,7 @@ var base = this base.$el = $("#minotaur") base.timeout = null - base.delay = 500 + base.delay = 1000 base.objects = {} base.init = function () { diff --git a/public/assets/javascripts/rectangles/util/undostack.js b/public/assets/javascripts/rectangles/util/undostack.js index b93c79e..959e3d1 100644 --- a/public/assets/javascripts/rectangles/util/undostack.js +++ b/public/assets/javascripts/rectangles/util/undostack.js @@ -31,16 +31,17 @@ this.types[ action.type ].redo(action.redo) return this.pointer < this.stack.length-1 } - UndoStack.prototype.register = function(actionType){ - if (actionType.length) { - actionType.forEach(this.registerOne.bind(this)) + UndoStack.prototype.register = function(actions){ + if (actions.length) { + actions.forEach(this.registerOne.bind(this)) } else { - this.registerOne(actionType) + this.registerOne(actions) } } - UndoStack.prototype.registerOne = function(actionType){ - this.types[ actionType.type ] = actionType + UndoStack.prototype.registerOne = function(action){ + if (! action.redo) { action.redo = action.undo } + this.types[ action.type ] = action } if ('window' in this) { window.UndoStack = new UndoStack diff --git a/public/assets/javascripts/ui/editor/LightControl.js b/public/assets/javascripts/ui/editor/LightControl.js index 84f2e58..76e9da1 100644 --- a/public/assets/javascripts/ui/editor/LightControl.js +++ b/public/assets/javascripts/ui/editor/LightControl.js @@ -1,39 +1,41 @@ var LightControl = View.extend({ - el: ".lightcontrol", - - events: { - "mousedown": "stopPropagation", - "click #wall-color": "editWallColor", - "click #outline-color": "editOutlineColor", - "click #floor-color": "editFloorColor", - "click #ceiling-color": "editCeilingColor", - "click label": "clickLabel", - "input #shadow-control": "updateShadow", - "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.$wallSwatch = this.$("#wall-color") - this.$outlineSwatch = this.$("#outline-color") - this.$floorSwatch = this.$("#floor-color") - this.$ceilingSwatch = this.$("#ceiling-color") - this.$brightnessControl = this.$("#brightness-control") - }, + 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") + }, + modes: [ "wall", "outline", "floor", "ceiling" ], + load: function(data){ - this.setWallColor(data.wall, false) - this.setOutlineColor(data.outline) - this.setFloorColor(data.floor) - this.setCeilingColor(data.ceiling) - this.setMode("wall") + 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(){ @@ -45,129 +47,85 @@ var LightControl = View.extend({ } this.load(colors) }, - - toggle: function(state){ + + 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 - switch (this.mode) { - case "wall": - this.setWallColor(rgb) - break - case "outline": - this.setOutlineColor(rgb) - break - case "floor": - this.setFloorColor(rgb) - break - case "ceiling": - this.setCeilingColor(rgb) - break - } - }, - - setMode: function (mode) { - var color, brightness - this.mode = mode + }, + + 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 + + Minotaur.watch( app.router.editorView.settings ) + }, + + setMode: function (mode) { + var color, brightness + this.mode = mode this.$swatches.removeClass("selected") this.$labels.removeClass("selected") - switch (mode) { - case "wall": - this.$wallSwatch.addClass("selected") - color = this.wallColor - break - case "outline": - this.$outlineSwatch.addClass("selected") - color = this.outlineColor - break - case "floor": - this.$floorSwatch.addClass("selected") - color = this.floorColor - break - case "ceiling": - this.$ceilingSwatch.addClass("selected") - color = this.ceilingColor - break - } + 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") - }, - editWallColor: function(){ - this.setMode("wall") - }, - editOutlineColor: function(){ - this.setMode("outline") - }, - - editFloorColor: function(){ - this.setMode("floor") - }, - - editCeilingColor: function(){ - this.setMode("ceiling") - }, - - setWallColor: function(rgb, repaint){ - repaint = typeof repaint != "undefined" ? repaint : true - var rgbColor = rgb_string(rgb) - var rgbaColor = rgba_string(rgb, app.defaults.wallOpacity) - Walls.colors.wall = this.wallColor = rgb - this.$wallSwatch.css("background-color", rgbColor) - Walls.forEach(function(wall){ - wall.outline(rgbaColor, null) - }) - }, - - setFloorColor: function(rgb, repaint){ - repaint = typeof repaint != "undefined" ? repaint : true - var rgbColor = rgb_string(rgb) - Walls.colors.floor = this.floorColor = rgb - this.$floorSwatch.css("background-color", rgbColor) - Rooms.forEach(function(room){ - room.setFloorColor(rgbColor) - }) - }, - - setCeilingColor: function(rgb, repaint){ - repaint = typeof repaint != "undefined" ? repaint : true - var rgbColor = rgb_string(rgb) - Walls.colors.ceiling = this.ceilingColor = rgb - this.$ceilingSwatch.css("background-color", rgbColor) - Rooms.forEach(function(room){ - room.setCeilingColor(rgbColor) - }) - }, - - setOutlineColor: function(rgb){ - repaint = typeof repaint != "undefined" ? repaint : true - var rgbColor = rgb_string(rgb) - Walls.colors.outline = this.outlineColor = rgb - this.$outlineSwatch.css("background-color", rgbColor) - Walls.forEach(function(wall){ - wall.outline(null, rgbColor) - }) - }, - - updateBrightness: function(){ - this.labColor[0] = parseFloat( this.$brightnessControl.val() ) - var rgb = this.colorPicker.setLab( this.labColor ) - this.pick(rgb, this.labColor) - }, + 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) + }, }) @@ -185,8 +143,6 @@ var LabColorPicker = function (parent, w, h) { canvas.height = h canvas.className = "colorPicker" - var down = false - var ww = w-1 var hh = h-1 @@ -197,16 +153,20 @@ var LabColorPicker = function (parent, w, h) { 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() } }) diff --git a/views/controls/editor/light-control.ejs b/views/controls/editor/light-control.ejs index 8536b74..a67df34 100644 --- a/views/controls/editor/light-control.ejs +++ b/views/controls/editor/light-control.ejs @@ -6,11 +6,11 @@
-
-
-
+
+
+

-
+