2150 |
mathias |
1 |
if(!dojo._hasResource["dojox.widget.ColorPicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
|
|
|
2 |
dojo._hasResource["dojox.widget.ColorPicker"] = true;
|
|
|
3 |
dojo.provide("dojox.widget.ColorPicker");
|
|
|
4 |
dojo.experimental("dojox.widget.ColorPicker"); // level: prototype
|
|
|
5 |
|
|
|
6 |
dojo.require("dijit.form._FormWidget");
|
|
|
7 |
dojo.require("dojo.dnd.move");
|
|
|
8 |
dojo.require("dojo.fx");
|
|
|
9 |
|
|
|
10 |
dojo.declare("dojox.widget.ColorPicker",
|
|
|
11 |
dijit.form._FormWidget,
|
|
|
12 |
{
|
|
|
13 |
// summary: a HSV color picker - like PhotoShop
|
|
|
14 |
//
|
|
|
15 |
// description:
|
|
|
16 |
// provides an interactive HSV ColorPicker similar to
|
|
|
17 |
// PhotoShop's color selction tool. Will eventually
|
|
|
18 |
// mixin FormWidget and be used as a suplement or a
|
|
|
19 |
// 'more interactive' replacement for ColorPalette
|
|
|
20 |
//
|
|
|
21 |
// example:
|
|
|
22 |
//
|
|
|
23 |
// code:
|
|
|
24 |
// var picker = new dojox.widget.ColorPicker({
|
|
|
25 |
// // a couple of example toggles:
|
|
|
26 |
// animatePoint:false,
|
|
|
27 |
// showHsv: false,
|
|
|
28 |
// webSafe: false,
|
|
|
29 |
// showRgb: false
|
|
|
30 |
// });
|
|
|
31 |
//
|
|
|
32 |
// markup:
|
|
|
33 |
// <div dojoType="dojox.widget.ColorPicker"></div>
|
|
|
34 |
//
|
|
|
35 |
|
|
|
36 |
// showRgb: Boolean
|
|
|
37 |
// show/update RGB input nodes
|
|
|
38 |
showRgb: true,
|
|
|
39 |
|
|
|
40 |
// showHsv: Boolean
|
|
|
41 |
// show/update HSV input nodes
|
|
|
42 |
showHsv: true,
|
|
|
43 |
|
|
|
44 |
// showHex: Boolean
|
|
|
45 |
// show/update Hex value field
|
|
|
46 |
showHex: true,
|
|
|
47 |
|
|
|
48 |
// webSafe: Boolean
|
|
|
49 |
// deprecated? or just use a toggle to show/hide that node, too?
|
|
|
50 |
webSafe: true,
|
|
|
51 |
|
|
|
52 |
// animatePoint: Boolean
|
|
|
53 |
// toggle to use slideTo (true) or just place the cursor (false) on click
|
|
|
54 |
animatePoint: true,
|
|
|
55 |
|
|
|
56 |
// slideDuration: Integer
|
|
|
57 |
// time in ms picker node will slide to next location (non-dragging) when animatePoint=true
|
|
|
58 |
slideDuration: 250,
|
|
|
59 |
|
|
|
60 |
_underlay: dojo.moduleUrl("dojox.widget","ColorPicker/images/underlay.png"),
|
|
|
61 |
templateString:"<div class=\"dojoxColorPicker\">\n\t<div class=\"dojoxColorPickerBox\">\n\t\t<div dojoAttachPoint=\"cursorNode\" class=\"dojoxColorPickerPoint\"></div>\n\t\t<img dojoAttachPoint=\"colorUnderlay\" dojoAttachEvent=\"onclick: _setPoint\" class=\"dojoxColorPickerUnderlay\" src=\"${_underlay}\">\n\t</div>\n\t<div class=\"dojoxHuePicker\">\n\t\t<div dojoAttachPoint=\"hueCursorNode\" class=\"dojoxHuePickerPoint\"></div>\n\t\t<div dojoAttachPoint=\"hueNode\" class=\"dojoxHuePickerUnderlay\" dojoAttachEvent=\"onclick: _setHuePoint\"></div>\n\t</div>\n\t<div dojoAttachPoint=\"previewNode\" class=\"dojoxColorPickerPreview\"></div>\n\t<div dojoAttachPoint=\"safePreviewNode\" class=\"dojoxColorPickerWebSafePreview\"></div>\n\t<div class=\"dojoxColorPickerOptional\">\n\t\t<div class=\"dijitInline dojoxColorPickerRgb\" dojoAttachPoint=\"rgbNode\">\n\t\t\t<table>\n\t\t\t<tr><td>r</td><td><input dojoAttachPoint=\"Rval\" size=\"1\"></td></tr>\n\t\t\t<tr><td>g</td><td><input dojoAttachPoint=\"Gval\" size=\"1\"></td></tr>\n\t\t\t<tr><td>b</td><td><input dojoAttachPoint=\"Bval\" size=\"1\"></td></tr>\n\t\t\t</table>\n\t\t</div>\n\t\t<div class=\"dijitInline dojoxColorPickerHsv\" dojoAttachPoint=\"hsvNode\">\n\t\t\t<table>\n\t\t\t<tr><td>h</td><td><input dojoAttachPoint=\"Hval\"size=\"1\"> °</td></tr>\n\t\t\t<tr><td>s</td><td><input dojoAttachPoint=\"Sval\" size=\"1\"> %</td></tr>\n\t\t\t<tr><td>v</td><td><input dojoAttachPoint=\"Vval\" size=\"1\"> %</td></tr>\n\t\t\t</table>\n\t\t</div>\n\t\t<div class=\"dojoxColorPickerHex\" dojoAttachPoint=\"hexNode\">\t\n\t\t\thex: <input dojoAttachPoint=\"hexCode, focusNode\" size=\"6\" class=\"dojoxColorPickerHexCode\">\n\t\t</div>\n\t</div>\n</div>\n",
|
|
|
62 |
|
|
|
63 |
postCreate: function(){
|
|
|
64 |
// summary: As quickly as we can, set up ie6 alpha-filter support for our
|
|
|
65 |
// underlay. we don't do image handles (done in css), just the 'core'
|
|
|
66 |
// of this widget: the underlay.
|
|
|
67 |
if(dojo.isIE && dojo.isIE<7){
|
|
|
68 |
this.colorUnderlay.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this._underlay+"', sizingMethod='scale')";
|
|
|
69 |
this.colorUnderlay.src = dojo.moduleUrl("dojox.widget","FisheyeList/blank.gif").toString();
|
|
|
70 |
}
|
|
|
71 |
// hide toggle-able nodes:
|
|
|
72 |
if (!this.showRgb){ this.rgbNode.style.display = "none"; }
|
|
|
73 |
if (!this.showHsv){ this.hsvNode.style.display = "none"; }
|
|
|
74 |
if (!this.showHex){ this.hexNode.style.display = "none"; }
|
|
|
75 |
if (!this.webSafe){ this.safePreviewNode.style.display = "none"; }
|
|
|
76 |
},
|
|
|
77 |
|
|
|
78 |
startup: function(){
|
|
|
79 |
// summary: defer all additional calls until we're started, and our
|
|
|
80 |
// embeded sliders are loaded? (not implemented yet)
|
|
|
81 |
|
|
|
82 |
// this._offset = ((dojo.marginBox(this.cursorNode).w)/2);
|
|
|
83 |
this._offset = 0;
|
|
|
84 |
|
|
|
85 |
this._mover = new dojo.dnd.Moveable(this.cursorNode, {
|
|
|
86 |
mover: dojo.dnd.boxConstrainedMover({ t:0, l:0, w:150, h:150 })
|
|
|
87 |
});
|
|
|
88 |
this._hueMover = new dojo.dnd.Moveable(this.hueCursorNode, {
|
|
|
89 |
mover: dojo.dnd.boxConstrainedMover({ t:0, l:0, w:0, h:150 })
|
|
|
90 |
});
|
|
|
91 |
|
|
|
92 |
// no dnd/move/move published ... use a timer:
|
|
|
93 |
dojo.subscribe("/dnd/move/stop",dojo.hitch(this,"_clearTimer"));
|
|
|
94 |
dojo.subscribe("/dnd/move/start",dojo.hitch(this,"_setTimer"));
|
|
|
95 |
|
|
|
96 |
// ugly scaling calculator. need a XYslider badly
|
|
|
97 |
this._sc = (1/dojo.coords(this.colorUnderlay).w);
|
|
|
98 |
this._hueSc = (255/(dojo.coords(this.hueNode).h+this._offset));
|
|
|
99 |
|
|
|
100 |
// initial color
|
|
|
101 |
this._updateColor();
|
|
|
102 |
|
|
|
103 |
},
|
|
|
104 |
|
|
|
105 |
_setTimer: function(/* dojo.dnd.Mover */mover){
|
|
|
106 |
this._timer = setInterval(dojo.hitch(this,"_updateColor"),45);
|
|
|
107 |
},
|
|
|
108 |
_clearTimer: function(/* dojo.dnd.Mover */mover){
|
|
|
109 |
clearInterval(this._timer);
|
|
|
110 |
this.onChange(this.value);
|
|
|
111 |
},
|
|
|
112 |
|
|
|
113 |
_setHue: function(/* Decimal */h){
|
|
|
114 |
// summary: sets a natural color background for the
|
|
|
115 |
// underlay image against closest hue value (full saturation)
|
|
|
116 |
// h: 0..255
|
|
|
117 |
|
|
|
118 |
// this is not a pretty conversion:
|
|
|
119 |
var hue = dojo.colorFromArray(this._hsv2rgb(h,1,1,{ inputRange: 1 })).toHex();
|
|
|
120 |
dojo.style(this.colorUnderlay,"backgroundColor",hue);
|
|
|
121 |
},
|
|
|
122 |
|
|
|
123 |
_updateColor: function(){
|
|
|
124 |
// summary: update the previewNode color, and input values [optional]
|
|
|
125 |
var h = Math.round((255+(this._offset))-((dojo.style(this.hueCursorNode,"top")+this._offset)*this._hueSc));
|
|
|
126 |
var s = Math.round((dojo.style(this.cursorNode,"left")*this._sc)*100);
|
|
|
127 |
var v = Math.round(100-(dojo.style(this.cursorNode,"top")*this._sc)*100);
|
|
|
128 |
|
|
|
129 |
// limit hue calculations to only when it changes
|
|
|
130 |
if(h != this._hue){ this._setHue(h); }
|
|
|
131 |
|
|
|
132 |
var rgb = this._hsv2rgb(h,s/100,v/100,{ inputRange: 1 });
|
|
|
133 |
var hex = (dojo.colorFromArray(rgb).toHex());
|
|
|
134 |
|
|
|
135 |
this.previewNode.style.backgroundColor = hex;
|
|
|
136 |
if(this.webSafe){ this.safePreviewNode.style.backgroundColor = hex; }
|
|
|
137 |
if(this.showHex){ this.hexCode.value = hex; }
|
|
|
138 |
if(this.showRgb){
|
|
|
139 |
this.Rval.value = rgb[0];
|
|
|
140 |
this.Gval.value = rgb[1];
|
|
|
141 |
this.Bval.value = rgb[2];
|
|
|
142 |
}
|
|
|
143 |
if(this.showHsv){
|
|
|
144 |
this.Hval.value = Math.round((h*360)/255); // convert to 0..360
|
|
|
145 |
this.Sval.value = s;
|
|
|
146 |
this.Vval.value = v;
|
|
|
147 |
}
|
|
|
148 |
this.value=hex;
|
|
|
149 |
|
|
|
150 |
// anytime we muck with the color, fire onChange?
|
|
|
151 |
if (!this._timer && !(arguments[1])){
|
|
|
152 |
this.setValue(this.value);
|
|
|
153 |
this.onChange(this.value);
|
|
|
154 |
}
|
|
|
155 |
},
|
|
|
156 |
|
|
|
157 |
_setHuePoint: function(/* Event */evt){
|
|
|
158 |
// summary: set the hue picker handle on relative y coordinates
|
|
|
159 |
if(this.animatePoint){
|
|
|
160 |
dojo.fx.slideTo({
|
|
|
161 |
node: this.hueCursorNode,
|
|
|
162 |
duration:this.slideDuration,
|
|
|
163 |
top: evt.layerY,
|
|
|
164 |
left: 0,
|
|
|
165 |
onEnd: dojo.hitch(this,"_updateColor")
|
|
|
166 |
}).play();
|
|
|
167 |
}else{
|
|
|
168 |
dojo.style(this.hueCursorNode,"top",(evt.layerY)+"px");
|
|
|
169 |
this._updateColor(false);
|
|
|
170 |
}
|
|
|
171 |
},
|
|
|
172 |
|
|
|
173 |
_setPoint: function(/* Event */evt){
|
|
|
174 |
// summary: set our picker point based on relative x/y coordinates
|
|
|
175 |
if(this.animatePoint){
|
|
|
176 |
dojo.fx.slideTo({
|
|
|
177 |
node: this.cursorNode,
|
|
|
178 |
duration:this.slideDuration,
|
|
|
179 |
top: evt.layerY-this._offset,
|
|
|
180 |
left: evt.layerX-this._offset,
|
|
|
181 |
onEnd: dojo.hitch(this,"_updateColor")
|
|
|
182 |
}).play();
|
|
|
183 |
}else{
|
|
|
184 |
dojo.style(this.cursorNode,"left",(evt.layerX-this._offset)+"px");
|
|
|
185 |
dojo.style(this.cursorNode,"top",(evt.layerY-this._offset)+"px");
|
|
|
186 |
this._updateColor(false);
|
|
|
187 |
}
|
|
|
188 |
},
|
|
|
189 |
|
|
|
190 |
// this ported directly from 0.4 dojo.gfx.colors.hsv, with bugs :)
|
|
|
191 |
// FIXME: use ttrenka's HSB ?
|
|
|
192 |
_hsv2rgb: function(/* int || Array */h, /* int */s, /* int */v, /* Object? */options){
|
|
|
193 |
// summary
|
|
|
194 |
// converts an HSV value set to RGB, ranges depending on optional options object.
|
|
|
195 |
// patch for options by Matthew Eernisse
|
|
|
196 |
if (dojo.isArray(h)) {
|
|
|
197 |
if(s){
|
|
|
198 |
options = s;
|
|
|
199 |
}
|
|
|
200 |
v = h[2] || 0;
|
|
|
201 |
s = h[1] || 0;
|
|
|
202 |
h = h[0] || 0;
|
|
|
203 |
}
|
|
|
204 |
|
|
|
205 |
var opt = {
|
|
|
206 |
inputRange: (options && options.inputRange) ? options.inputRange : [255, 255, 255],
|
|
|
207 |
outputRange: (options && options.outputRange) ? options.outputRange : 255
|
|
|
208 |
};
|
|
|
209 |
|
|
|
210 |
switch(opt.inputRange[0]) {
|
|
|
211 |
// 0.0-1.0
|
|
|
212 |
case 1: h = h * 360; break;
|
|
|
213 |
// 0-100
|
|
|
214 |
case 100: h = (h / 100) * 360; break;
|
|
|
215 |
// 0-360
|
|
|
216 |
case 360: h = h; break;
|
|
|
217 |
// 0-255
|
|
|
218 |
default: h = (h / 255) * 360;
|
|
|
219 |
}
|
|
|
220 |
if (h == 360){ h = 0;}
|
|
|
221 |
|
|
|
222 |
// no need to alter if inputRange[1] = 1
|
|
|
223 |
switch(opt.inputRange[1]){
|
|
|
224 |
case 100: s /= 100; break;
|
|
|
225 |
case 255: s /= 255;
|
|
|
226 |
}
|
|
|
227 |
|
|
|
228 |
// no need to alter if inputRange[1] = 1
|
|
|
229 |
switch(opt.inputRange[2]){
|
|
|
230 |
case 100: v /= 100; break;
|
|
|
231 |
case 255: v /= 255;
|
|
|
232 |
}
|
|
|
233 |
|
|
|
234 |
var r = null;
|
|
|
235 |
var g = null;
|
|
|
236 |
var b = null;
|
|
|
237 |
|
|
|
238 |
if (s == 0){
|
|
|
239 |
// color is on black-and-white center line
|
|
|
240 |
// achromatic: shades of gray
|
|
|
241 |
r = v;
|
|
|
242 |
g = v;
|
|
|
243 |
b = v;
|
|
|
244 |
}else{
|
|
|
245 |
// chromatic color
|
|
|
246 |
var hTemp = h / 60; // h is now IN [0,6]
|
|
|
247 |
var i = Math.floor(hTemp); // largest integer <= h
|
|
|
248 |
var f = hTemp - i; // fractional part of h
|
|
|
249 |
|
|
|
250 |
var p = v * (1 - s);
|
|
|
251 |
var q = v * (1 - (s * f));
|
|
|
252 |
var t = v * (1 - (s * (1 - f)));
|
|
|
253 |
|
|
|
254 |
switch(i){
|
|
|
255 |
case 0: r = v; g = t; b = p; break;
|
|
|
256 |
case 1: r = q; g = v; b = p; break;
|
|
|
257 |
case 2: r = p; g = v; b = t; break;
|
|
|
258 |
case 3: r = p; g = q; b = v; break;
|
|
|
259 |
case 4: r = t; g = p; b = v; break;
|
|
|
260 |
case 5: r = v; g = p; b = q; break;
|
|
|
261 |
}
|
|
|
262 |
}
|
|
|
263 |
|
|
|
264 |
switch(opt.outputRange){
|
|
|
265 |
case 1:
|
|
|
266 |
r = dojo.math.round(r, 2);
|
|
|
267 |
g = dojo.math.round(g, 2);
|
|
|
268 |
b = dojo.math.round(b, 2);
|
|
|
269 |
break;
|
|
|
270 |
case 100:
|
|
|
271 |
r = Math.round(r * 100);
|
|
|
272 |
g = Math.round(g * 100);
|
|
|
273 |
b = Math.round(b * 100);
|
|
|
274 |
break;
|
|
|
275 |
default:
|
|
|
276 |
r = Math.round(r * 255);
|
|
|
277 |
g = Math.round(g * 255);
|
|
|
278 |
b = Math.round(b * 255);
|
|
|
279 |
}
|
|
|
280 |
return [r, g, b];
|
|
|
281 |
}
|
|
|
282 |
});
|
|
|
283 |
|
|
|
284 |
}
|