Start drawing the color wheel with HTML5 canvas.
[rgbconverter.git] / RGB Converter.wdgt / Widget.js
1 /*=====================================================================*\
2 || ###################################################################
3 || # RGB Converter
4 || # Copyright (c)2002-2010 Blue Static
5 || #
6 || # This program is free software; you can redistribute it and/or modify
7 || # it under the terms of the GNU General Public License as published by
8 || # the Free Software Foundation; version 2 of the License.
9 || #
10 || # This program is distributed in the hope that it will be useful, but
11 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 || # more details.
14 || #
15 || # You should have received a copy of the GNU General Public License along
16 || # with this program; if not, write to the Free Software Foundation, Inc.,
17 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
18 || ###################################################################
19 \*=====================================================================*/
20
21 var colors_ = {
22 red : 60,
23 green : 60,
24 blue : 60,
25 hex : '3C3C3C'
26 };
27
28 // ###################################################################
29 // widget init
30 function setup()
31 {
32 Draw();
33 createGenericButton(document.getElementById("backbutton"), "Done", hide_back, 0);
34 document.getElementById("revision").innerHTML = "(r" + document.getElementById("revision").innerHTML.replace(/[^0-9]/g, "") + ")";
35 }
36
37 // ###################################################################
38 // watches the three RGB fields to make sure they don't go over the limites
39 function rgbwatcher(colour)
40 {
41 field = document.getElementById(colour + "inputf");
42
43 // handle RGB triads
44 if (triad = field.value.match(/(rgb)?\(?([0-9]{1,3}),\s?([0-9]{1,3}),\s?([0-9]{1,3})\)?/))
45 {
46 document.getElementById("redinputf").value = triad[2];
47 document.getElementById("greeninputf").value = triad[3];
48 document.getElementById("blueinputf").value = triad[4];
49
50 rgbwatcher("red");
51 rgbwatcher("green");
52 rgbwatcher("blue");
53 return;
54 }
55
56 // sanitize the number
57 var newval = field.value.replace(/[^0-9\-\.]*/g, "");
58 newval = Math.floor(newval);
59
60 // make sure we don't go over 255
61 if (newval > 255)
62 {
63 newval = 255;
64 }
65 else if (newval < 0)
66 {
67 newval = 0;
68 }
69
70 // update the text field
71 field.value = newval;
72
73 // set fields[]
74 fields[colour] = newval;
75
76 // set hex
77 update_hex();
78
79 // redraw the swatch
80 update_swatch();
81 }
82
83 // ###################################################################
84 function Draw()
85 {
86 var canvas = document.getElementById('wheel');
87 var context = canvas.getContext('2d');
88 var radius = canvas.width / 2 - 3;
89 var center = [canvas.width / 2, canvas.height / 2];
90 context.strokeStyle = 'black';
91
92 // Draw the individual components. Start with red.
93 context.beginPath();
94 context.moveTo(center[0], center[1]);
95 context.arc(canvas.width / 2,
96 canvas.height / 2,
97 radius,
98 Math.PI * 4/3,
99 Math.PI * 6/3,
100 false);
101 context.lineTo(center[0], center[1]);
102 context.fillStyle = _GetComponentColorString('red');
103 context.fill();
104 context.stroke();
105
106 // Green component.
107 context.beginPath();
108 context.moveTo(center[0], center[1]);
109 context.arc(canvas.width / 2,
110 canvas.height / 2,
111 radius,
112 Math.PI * 0,
113 Math.PI * 2/3,
114 false);
115 context.lineTo(center[0], center[1]);
116 context.fillStyle = _GetComponentColorString('green');
117 context.fill();
118 context.stroke();
119
120 // Blue component.
121 context.beginPath();
122 context.moveTo(center[0], center[1]);
123 context.arc(canvas.width / 2,
124 canvas.height / 2,
125 radius,
126 Math.PI * 2/3,
127 Math.PI * 4/3,
128 false);
129 context.lineTo(center[0], center[1]);
130 context.fillStyle = _GetComponentColorString('blue');
131 context.fill();
132 context.stroke();
133
134 // Draw the sheen gradient.
135 context.beginPath();
136 context.arc(center[0], center[1], radius, 0, Math.PI * 2, true);
137 var gradient = context.createLinearGradient(0, 0, 0, canvas.height);
138 gradient.addColorStop(0, 'rgba(255,255,255,.5)');
139 gradient.addColorStop(1, 'rgba(0,0,0,0)');
140 context.fillStyle = gradient;
141 context.fill();
142 context.closePath();
143
144 // Draw the inner wheel.
145 context.beginPath();
146 context.arc(center[0], center[1], canvas.width / 4.5, 0, Math.PI * 2, true);
147 context.fillStyle = _GetRGBColorString();
148 context.fill();
149 context.strokeStyle = 'black';
150 context.stroke();
151 context.closePath();
152 }
153
154 // ###################################################################
155 // Returns the rgb(,,,) color string.
156
157 function _GetRGBColorString()
158 {
159 return 'rgb(' + colors_.red + ',' + colors_.green + ',' + colors_.blue + ')';
160 }
161
162 // ###################################################################
163 // Returns an individual color component's color string.
164
165 function _GetComponentColorString(color)
166 {
167 if (color == 'red') {
168 return 'rgb(' + colors_.red + ',0,0)';
169 } else if (color == 'green') {
170 return 'rgb(0,' + colors_.green + ',0)';
171 } else if (color == 'blue') {
172 return 'rgb(0,0,' + colors_.blue + ')';
173 }
174 alert('Invalid color ' + color);
175 }
176
177 // ###################################################################
178 // watches the hex field for updates
179 function hexwatcher()
180 {
181 field = document.getElementById("hexinputf");
182
183 // sanitize the hex
184 var newval = field.value.replace(/[^0-9a-f]*/gi, "");
185
186 // get the length
187 var length = newval.length;
188
189 // make sure we're always 6
190 if (length > 6)
191 {
192 newval = newval.substr(0, 6);
193 }
194 else if (length == 3)
195 {
196 newval = newval.substr(0, 1) + newval.substr(0, 1) + newval.substr(1, 1) + newval.substr(1, 1) + newval.substr(2, 1) + newval.substr(2, 1);
197 }
198 else if (length < 6)
199 {
200 for (var i = length; i <= 6; i++)
201 {
202 newval = "" + newval + "0";
203 }
204 }
205
206 // update the field
207 field.value = newval;
208
209 // update fields[]
210 fields['hex'] = newval;
211
212 // set RGB
213 update_rgb();
214
215 // redraw the swatch
216 update_swatch();
217 }
218
219 // ###################################################################
220 // update the hex value
221 function update_hex()
222 {
223 var hexstr = dec2hex(fields['red']) + dec2hex(fields['green']) + dec2hex(fields['blue']);
224 fields['hex'] = hexstr;
225 document.getElementById("hexinputf").value = hexstr;
226 }
227
228 // ###################################################################
229 // update the RGB values
230 function update_rgb()
231 {
232 // regex match the bits
233 var bits = fields['hex'].match(/(..)(..)(..)/);
234
235 fields['red'] = hex2dec(bits[1]);
236 fields['green'] = hex2dec(bits[2]);
237 fields['blue'] = hex2dec(bits[3]);
238
239 // construct the hex values
240 document.getElementById("redinputf").value = fields['red'];
241 document.getElementById("greeninputf").value = fields['green'];
242 document.getElementById("blueinputf").value = fields['blue'];
243 }
244
245 // ###################################################################
246 // update the colour swatch
247 function update_swatch()
248 {
249 document.getElementById("hexinputf").value = document.getElementById("hexinputf").value.toUpperCase();
250 document.getElementById("swatch").style.backgroundColor = "rgb(" + fields['red'] + ", " + fields['green'] + ", " + fields['blue'] + ")";
251 document.getElementById("swatch-red").style.backgroundColor = "rgb(" + fields['red'] + ", 0, 0)";
252 document.getElementById("swatch-green").style.backgroundColor = "rgb(0, " + fields['green'] + ", 0)";
253 document.getElementById("swatch-blue").style.backgroundColor = "rgb(0, 0, " + fields['blue'] + ")";
254 }
255
256 // ###################################################################
257 // convert a decimal to a hexidecimal
258 function dec2hex(dec)
259 {
260 var hexstr = "0123456789ABCDEF";
261 var low = dec % 16;
262 var high = (dec - low) / 16;
263 hex = "" + hexstr.charAt(high) + hexstr.charAt(low);
264
265 return hex.toString();
266 }
267
268 // ###################################################################
269 // converts a hexidecimal to a decimal
270 function hex2dec(hex)
271 {
272 return parseInt(hex, 16);
273 }
274
275 // ###################################################################
276 // ###################################################################
277 // ###################################################################
278
279 // flip data
280
281 function show_back()
282 {
283 var front = document.getElementById("front");
284 var back = document.getElementById("back");
285
286 if (window.widget)
287 {
288 widget.prepareForTransition("ToBack");
289 }
290
291 front.style.display = "none";
292 back.style.display = "block";
293
294 if (window.widget)
295 {
296 setTimeout("widget.performTransition();", 0);
297 }
298
299 document.getElementById("fliprollie").style.display = "none";
300 }
301
302 function hide_back()
303 {
304 var front = document.getElementById("front");
305 var back = document.getElementById("back");
306
307 if (window.widget)
308 {
309 widget.prepareForTransition("ToFront");
310 }
311
312 back.style.display = "none";
313 front.style.display = "block";
314
315 if (window.widget)
316 {
317 setTimeout("widget.performTransition();", 0);
318 }
319 }
320
321 var flipShown = false;
322
323 var animation = {
324 duration : 0,
325 starttime : 0,
326 to : 1.0,
327 now : 0.0,
328 from : 0.0,
329 firstElement : null,
330 timer : null
331 };
332
333 function mousemove(event)
334 {
335 if (!flipShown)
336 {
337 if (animation.timer != null)
338 {
339 clearInterval(animation.timer);
340 animation.timer = null;
341 }
342
343 var starttime = (new Date).getTime() - 13;
344
345 animation.duration = 500;
346 animation.starttime = starttime;
347 animation.firstElement = document.getElementById("flip");
348 animation.timer = setInterval("animate();", 13);
349 animation.from = animation.now;
350 animation.to = 1.0;
351 animate();
352 flipShown = true;
353 }
354 }
355
356 function mouseexit(event)
357 {
358 if (flipShown)
359 {
360 // fade in the flip widget
361 if (animation.timer != null)
362 {
363 clearInterval (animation.timer);
364 animation.timer = null;
365 }
366
367 var starttime = (new Date).getTime() - 13;
368
369 animation.duration = 500;
370 animation.starttime = starttime;
371 animation.firstElement = document.getElementById("flip");
372 animation.timer = setInterval("animate();", 13);
373 animation.from = animation.now;
374 animation.to = 0.0;
375 animate();
376 flipShown = false;
377 }
378 }
379
380
381 function animate()
382 {
383 var T;
384 var ease;
385 var time = (new Date).getTime();
386
387 T = limit_3(time - animation.starttime, 0, animation.duration);
388
389 if (T >= animation.duration)
390 {
391 clearInterval(animation.timer);
392 animation.timer = null;
393 animation.now = animation.to;
394 }
395 else
396 {
397 ease = 0.5 - (0.5 * Math.cos(Math.PI * T / animation.duration));
398 animation.now = compute_next_float(animation.from, animation.to, ease);
399 }
400
401 animation.firstElement.style.opacity = animation.now;
402 }
403
404 function limit_3 (a, b, c)
405 {
406 return a < b ? b : (a > c ? c : a);
407 }
408
409 function compute_next_float(from, to, ease)
410 {
411 return from + (to - from) * ease;
412 }
413
414 function enterflip(event)
415 {
416 document.getElementById("fliprollie").style.display = "block";
417 }
418
419 function exitflip(event)
420 {
421 document.getElementById("fliprollie").style.display = "none";
422 }
423
424 /*=====================================================================*\
425 || ###################################################################
426 || # $HeadURL$
427 || # $Id$
428 || ###################################################################
429 \*=====================================================================*/