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" var brightnessControl = this.brightness = document.createElement("input") var $brightnessControl = $(brightnessControl) brightnessControl.setAttribute("type", "range") brightnessControl.setAttribute("min", "0") brightnessControl.setAttribute("max", "110") brightnessControl.setAttribute("value", "0") 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() } }) $brightnessControl.on({ "mousedown": function(){ base.beginBrightness() }, "input": function(){ base.updateBrightness() }, }) 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){ i = clamp(i, 0, w) j = clamp(j, 0, h) 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) this.moveCursor(i, j) parent.pickColor( 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 ) this.moveCursor(x,y) this.setLab(Lab) this.setBrightness(Lab) return Lab } this.moveCursor = function(x,y){ cursor.style.left = x + "px" cursor.style.top = y + "px" } 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) } this.beginBrightness = function(){ parent.begin() $(window).one("mouseup", parent.finalize.bind(parent)) } this.updateBrightness = function(){ parent.labColor[0] = parseFloat( $brightnessControl.val() ) var rgb = base.setLab( parent.labColor ) parent.pickColor(rgb, parent.labColor) } this.setBrightness = function(Lab){ $brightnessControl.val(Lab[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 = Math.pow( ( var_R + 0.055 ) / 1.055, 2.4) else var_R = var_R / 12.92 if ( var_G > 0.04045 ) var_G = Math.pow( ( var_G + 0.055 ) / 1.055, 2.4) else var_G = var_G / 12.92 if ( var_B > 0.04045 ) var_B = Math.pow( ( 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] } }