Browse files

Added color picker

  • Loading branch information...
1 parent ffd6a43 commit 271968f7545155167d33cbce68656bafdbcedb74 @tj tj committed Oct 10, 2011
View
8 Makefile
@@ -1,7 +1,13 @@
+COMPONENTS = emitter \
+ dialog \
+ overlay \
+ confirmation \
+ color-picker
+
ui:
@rm -fr build
@mkdir build
- @./support/build.js emitter dialog overlay confirmation
+ @./support/build.js $(COMPONENTS)
.PHONY: ui
View
4 build/ui.css
@@ -89,4 +89,6 @@
text-align: right;
background: #fafafa;
-webkit-box-shadow: inset 0 1px 0 white;
-}
+}.color-picker canvas {
+ cursor: crosshair;
+}
View
326 build/ui.js
@@ -422,4 +422,328 @@ Confirmation.prototype.render = function(options){
});
};
-})(ui, "<div class=\"actions\">\n <button class=\"cancel\">Cancel</button>\n <button class=\"ok main\">Ok</button>\n</div>");
+})(ui, "<div class=\"actions\">\n <button class=\"cancel\">Cancel</button>\n <button class=\"ok main\">Ok</button>\n</div>");
+;(function(exports, html){
+
+/**
+ * Expose `ColorPicker`.
+ */
+
+exports.ColorPicker = ColorPicker;
+
+/**
+ * RGB util.
+ */
+
+function rgb(r,g,b) {
+ return 'rgb(' + r + ', ' + g + ', ' + b + ')';
+}
+
+/**
+ * RGBA util.
+ */
+
+function rgba(r,g,b,a) {
+ return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
+}
+
+/**
+ * Initialize a new `ColorPicker`.
+ *
+ * @param {Type} name
+ * @return {Type}
+ * @api public
+ */
+
+function ColorPicker() {
+ ui.Emitter.call(this);
+ this.template = html;
+ this.el = $(this.template);
+ this.main = this.el.find('.main').get(0);
+ this.spectrum = this.el.find('.spectrum').get(0);
+ this.width(180);
+ this.height(180);
+ this.hue(rgb(255, 0, 0));
+ this.spectrumEvents();
+ this.mainEvents();
+}
+
+/**
+ * Inherit from `Emitter.prototype`.
+ */
+
+ColorPicker.prototype = new ui.Emitter;
+
+/**
+ * Set width / height to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.size = function(n){
+ return this
+ .width(n)
+ .height(n);
+};
+
+/**
+ * Set width to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.width = function(n){
+ this.w = n;
+ return this;
+};
+
+/**
+ * Set height to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.height = function(n){
+ this.h = n;
+ return this;
+};
+
+/**
+ * Spectrum related events.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.spectrumEvents = function(){
+ var self = this
+ , canvas = $(this.spectrum)
+ , down;
+
+ function update(e) {
+ var color = self.hueAt(e.offsetY);
+ self.hue(color.toString());
+ self.emit('change', color);
+ self.render({ hue: e.offsetY });
+ }
+
+ canvas.mousedown(function(e){
+ down = true;
+ update(e);
+ });
+
+ canvas.mousemove(function(e){
+ if (down) update(e);
+ });
+
+ canvas.mouseup(function(){
+ down = false;
+ });
+};
+
+/**
+ * Hue / lightness events.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.mainEvents = function(){
+ var self = this
+ , canvas = $(this.main)
+ , down;
+
+ function update(e) {
+ var color = self.colorAt(e.offsetX, e.offsetY);
+ self.color(color.toString());
+ self.emit('change', color);
+ self.render({ color: [e.offsetX, e.offsetY]});
+ }
+
+ canvas.mousedown(function(e){
+ down = true;
+ update(e);
+ });
+
+ canvas.mousemove(function(e){
+ if (down) update(e);
+ });
+
+ canvas.mouseup(function(){
+ down = false;
+ });
+};
+
+/**
+ * Get the RGB color at `(x, y)`.
+ *
+ * @param {Number} x
+ * @param {Number} y
+ * @return {Object}
+ * @api private
+ */
+
+ColorPicker.prototype.colorAt = function(x, y){
+ var data = this.main.getContext('2d').getImageData(x, y, 1, 1).data;
+ return {
+ r: data[0]
+ , g: data[1]
+ , b: data[2]
+ , toString: function(){
+ return rgb(this.r, this.g, this.b);
+ }
+ };
+};
+
+/**
+ * Get the RGB value at `y`.
+ *
+ * @param {Type} name
+ * @return {Type}
+ * @api private
+ */
+
+ColorPicker.prototype.hueAt = function(y){
+ var data = this.spectrum.getContext('2d').getImageData(0, y, 1, 1).data;
+ return {
+ r: data[0]
+ , g: data[1]
+ , b: data[2]
+ , toString: function(){
+ return rgb(this.r, this.g, this.b);
+ }
+ };
+};
+
+/**
+ * Get or set `color`.
+ *
+ * @param {String} color
+ * @return {String|ColorPicker}
+ * @api public
+ */
+
+ColorPicker.prototype.color = function(color){
+ if (0 == arguments.length) return this._color;
+ this._color = color;
+ return this;
+};
+
+/**
+ * Get or set hue `color`.
+ *
+ * @param {String} color
+ * @return {String|ColorPicker}
+ * @api public
+ */
+
+ColorPicker.prototype.hue = function(color){
+ if (0 == arguments.length) return this._hue;
+ this._hue = color;
+ return this;
+};
+
+/**
+ * Render with the given `options`.
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+ColorPicker.prototype.render = function(options){
+ options = options || {};
+ this.renderMain(options);
+ this.renderSpectrum(options);
+};
+
+/**
+ * Render spectrum.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.renderSpectrum = function(options){
+ var el = this.el
+ , canvas = this.spectrum
+ , ctx = canvas.getContext('2d')
+ , pos = options.hue || 0
+ , w = this.w * .12
+ , h = this.h;
+
+ canvas.width = w;
+ canvas.height = h;
+
+ var grad = ctx.createLinearGradient(0, 0, 0, h);
+ grad.addColorStop(0, rgb(255, 0, 0));
+ grad.addColorStop(.15, rgb(255, 0, 255));
+ grad.addColorStop(.33, rgb(0, 0, 255));
+ grad.addColorStop(.49, rgb(0, 255, 255));
+ grad.addColorStop(.67, rgb(0, 255, 0));
+ grad.addColorStop(.84, rgb(255, 255, 0));
+ grad.addColorStop(1, rgb(255, 0, 0));
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ // pos
+ ctx.fillStyle = rgba(0, 0, 0, .3);
+ ctx.fillRect(0, pos, w, 1);
+};
+
+/**
+ * Render hue/luminosity canvas.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.renderMain = function(options){
+ var el = this.el
+ , canvas = this.main
+ , ctx = canvas.getContext('2d')
+ , w = this.w
+ , h = this.h
+ , pos = options.color || [w, 0]
+ , x = pos[0] + .5
+ , y = pos[1] + .5;
+
+ canvas.width = w;
+ canvas.height = h;
+
+ var grad = ctx.createLinearGradient(0, 0, w, 0);
+ grad.addColorStop(0, rgb(255, 255, 255));
+ grad.addColorStop(1, this._hue);
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ grad = ctx.createLinearGradient(0, 0, 0, h);
+ grad.addColorStop(0, rgba(255, 255, 255, 0));
+ grad.addColorStop(1, rgba(0, 0, 0, 1));
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ // pos
+ var rad = 10;
+ ctx.save();
+ ctx.beginPath();
+ ctx.lineWidth = 1;
+
+ // outer dark
+ ctx.strokeStyle = rgba(0,0,0,.5);
+ ctx.arc(x, y, rad / 2, 0, Math.PI * 2, false);
+ ctx.stroke();
+
+ // outer light
+ ctx.strokeStyle = rgba(255,255,255,.5);
+ ctx.arc(x, y, rad / 2 - 1, 0, Math.PI * 2, false);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.restore();
+};
+})(ui, "<div class=\"color-picker\">\n <canvas class=\"main\"></canvas>\n <canvas class=\"spectrum\"></canvas>\n</div>");
View
3 lib/components/color-picker/color-picker.css
@@ -0,0 +1,3 @@
+.color-picker canvas {
+ cursor: crosshair;
+}
View
4 lib/components/color-picker/color-picker.html
@@ -0,0 +1,4 @@
+<div class="color-picker">
+ <canvas class="main"></canvas>
+ <canvas class="spectrum"></canvas>
+</div>
View
322 lib/components/color-picker/color-picker.js
@@ -0,0 +1,322 @@
+
+/**
+ * Expose `ColorPicker`.
+ */
+
+exports.ColorPicker = ColorPicker;
+
+/**
+ * RGB util.
+ */
+
+function rgb(r,g,b) {
+ return 'rgb(' + r + ', ' + g + ', ' + b + ')';
+}
+
+/**
+ * RGBA util.
+ */
+
+function rgba(r,g,b,a) {
+ return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + a + ')';
+}
+
+/**
+ * Initialize a new `ColorPicker`.
+ *
+ * @param {Type} name
+ * @return {Type}
+ * @api public
+ */
+
+function ColorPicker() {
+ ui.Emitter.call(this);
+ this.template = html;
+ this.el = $(this.template);
+ this.main = this.el.find('.main').get(0);
+ this.spectrum = this.el.find('.spectrum').get(0);
+ this.width(180);
+ this.height(180);
+ this.hue(rgb(255, 0, 0));
+ this.spectrumEvents();
+ this.mainEvents();
+}
+
+/**
+ * Inherit from `Emitter.prototype`.
+ */
+
+ColorPicker.prototype = new ui.Emitter;
+
+/**
+ * Set width / height to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.size = function(n){
+ return this
+ .width(n)
+ .height(n);
+};
+
+/**
+ * Set width to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.width = function(n){
+ this.w = n;
+ return this;
+};
+
+/**
+ * Set height to `n`.
+ *
+ * @param {Number} n
+ * @return {ColorPicker} for chaining
+ * @api public
+ */
+
+ColorPicker.prototype.height = function(n){
+ this.h = n;
+ return this;
+};
+
+/**
+ * Spectrum related events.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.spectrumEvents = function(){
+ var self = this
+ , canvas = $(this.spectrum)
+ , down;
+
+ function update(e) {
+ var color = self.hueAt(e.offsetY);
+ self.hue(color.toString());
+ self.emit('change', color);
+ self.render({ hue: e.offsetY });
+ }
+
+ canvas.mousedown(function(e){
+ down = true;
+ update(e);
+ });
+
+ canvas.mousemove(function(e){
+ if (down) update(e);
+ });
+
+ canvas.mouseup(function(){
+ down = false;
+ });
+};
+
+/**
+ * Hue / lightness events.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.mainEvents = function(){
+ var self = this
+ , canvas = $(this.main)
+ , down;
+
+ function update(e) {
+ var color = self.colorAt(e.offsetX, e.offsetY);
+ self.color(color.toString());
+ self.emit('change', color);
+ self.render({ color: [e.offsetX, e.offsetY]});
+ }
+
+ canvas.mousedown(function(e){
+ down = true;
+ update(e);
+ });
+
+ canvas.mousemove(function(e){
+ if (down) update(e);
+ });
+
+ canvas.mouseup(function(){
+ down = false;
+ });
+};
+
+/**
+ * Get the RGB color at `(x, y)`.
+ *
+ * @param {Number} x
+ * @param {Number} y
+ * @return {Object}
+ * @api private
+ */
+
+ColorPicker.prototype.colorAt = function(x, y){
+ var data = this.main.getContext('2d').getImageData(x, y, 1, 1).data;
+ return {
+ r: data[0]
+ , g: data[1]
+ , b: data[2]
+ , toString: function(){
+ return rgb(this.r, this.g, this.b);
+ }
+ };
+};
+
+/**
+ * Get the RGB value at `y`.
+ *
+ * @param {Type} name
+ * @return {Type}
+ * @api private
+ */
+
+ColorPicker.prototype.hueAt = function(y){
+ var data = this.spectrum.getContext('2d').getImageData(0, y, 1, 1).data;
+ return {
+ r: data[0]
+ , g: data[1]
+ , b: data[2]
+ , toString: function(){
+ return rgb(this.r, this.g, this.b);
+ }
+ };
+};
+
+/**
+ * Get or set `color`.
+ *
+ * @param {String} color
+ * @return {String|ColorPicker}
+ * @api public
+ */
+
+ColorPicker.prototype.color = function(color){
+ if (0 == arguments.length) return this._color;
+ this._color = color;
+ return this;
+};
+
+/**
+ * Get or set hue `color`.
+ *
+ * @param {String} color
+ * @return {String|ColorPicker}
+ * @api public
+ */
+
+ColorPicker.prototype.hue = function(color){
+ if (0 == arguments.length) return this._hue;
+ this._hue = color;
+ return this;
+};
+
+/**
+ * Render with the given `options`.
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+ColorPicker.prototype.render = function(options){
+ options = options || {};
+ this.renderMain(options);
+ this.renderSpectrum(options);
+};
+
+/**
+ * Render spectrum.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.renderSpectrum = function(options){
+ var el = this.el
+ , canvas = this.spectrum
+ , ctx = canvas.getContext('2d')
+ , pos = options.hue || 0
+ , w = this.w * .12
+ , h = this.h;
+
+ canvas.width = w;
+ canvas.height = h;
+
+ var grad = ctx.createLinearGradient(0, 0, 0, h);
+ grad.addColorStop(0, rgb(255, 0, 0));
+ grad.addColorStop(.15, rgb(255, 0, 255));
+ grad.addColorStop(.33, rgb(0, 0, 255));
+ grad.addColorStop(.49, rgb(0, 255, 255));
+ grad.addColorStop(.67, rgb(0, 255, 0));
+ grad.addColorStop(.84, rgb(255, 255, 0));
+ grad.addColorStop(1, rgb(255, 0, 0));
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ // pos
+ ctx.fillStyle = rgba(0, 0, 0, .3);
+ ctx.fillRect(0, pos, w, 1);
+};
+
+/**
+ * Render hue/luminosity canvas.
+ *
+ * @api private
+ */
+
+ColorPicker.prototype.renderMain = function(options){
+ var el = this.el
+ , canvas = this.main
+ , ctx = canvas.getContext('2d')
+ , w = this.w
+ , h = this.h
+ , pos = options.color || [w, 0]
+ , x = pos[0] + .5
+ , y = pos[1] + .5;
+
+ canvas.width = w;
+ canvas.height = h;
+
+ var grad = ctx.createLinearGradient(0, 0, w, 0);
+ grad.addColorStop(0, rgb(255, 255, 255));
+ grad.addColorStop(1, this._hue);
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ grad = ctx.createLinearGradient(0, 0, 0, h);
+ grad.addColorStop(0, rgba(255, 255, 255, 0));
+ grad.addColorStop(1, rgba(0, 0, 0, 1));
+
+ ctx.fillStyle = grad;
+ ctx.fillRect(0, 0, w, h);
+
+ // pos
+ var rad = 10;
+ ctx.save();
+ ctx.beginPath();
+ ctx.lineWidth = 1;
+
+ // outer dark
+ ctx.strokeStyle = rgba(0,0,0,.5);
+ ctx.arc(x, y, rad / 2, 0, Math.PI * 2, false);
+ ctx.stroke();
+
+ // outer light
+ ctx.strokeStyle = rgba(255,255,255,.5);
+ ctx.arc(x, y, rad / 2 - 1, 0, Math.PI * 2, false);
+ ctx.stroke();
+
+ ctx.beginPath();
+ ctx.restore();
+};
View
19 test/index.html
@@ -89,7 +89,22 @@
});
return false;
});
-
+
+ var picker = new ui.ColorPicker;
+ picker.render();
+ picker.el.appendTo('body');
+ picker.on('change', function(color){
+ $('#color').css({
+ background: color
+ , width: 50
+ , height: 50
+ });
+ });
+
+ $('li:nth-child(9) a').click(function(){
+ new ui.ColorPicker().show();
+ return false;
+ });
});
</script>
<style>
@@ -109,6 +124,8 @@
<li><a href="#">Confirmation with overlay</a></li>
<li><a href="#">Confirmation with modal overlay</a></li>
<li><a href="#">Confirmation with events</a></li>
+ <li><a href="#">Color picker</a></li>
</ul>
+ <div id="color">s</div>
</body>
</html>

0 comments on commit 271968f

Please sign in to comment.