~ubuntu-branches/ubuntu/quantal/xdaliclock/quantal

« back to all changes in this revision

Viewing changes to webos/DaliClock/app/assistants/daliclock.js

  • Committer: Bazaar Package Importer
  • Author(s): Kartik Mistry
  • Date: 2010-04-20 08:42:20 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20100420084220-j7ykvh34b2jx7hyv
Tags: 2.31-1
* New maintainer (Closes: #561233)
* New upstream release (Closes: #578379)
* debian/control:
  + Updated to Standards-Version 3.8.4
  + Added ${misc:Depends} to Depends
  + Updated debhelper dependency to 7
* debian/rules:
  + Do not do append to copyright file trick
  + Used dh_prep instead of dh_clean -k
* Converted package to new source format 3.0 (quilt)
* debian/copyright:
  + Added missing vroot.h copyright
  + Better copyright assignment, year for Author
* debian/patches/spelling-error-in-manpage_xdaliclock:
  + Added patch to fix manpage spelling mistake by Florian Ernst
    <florian@debian.org>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Dali Clock - a melting digital clock for Palm WebOS.
 
2
 * Copyright (c) 1991-2009 Jamie Zawinski <jwz@jwz.org>
 
3
 *
 
4
 * Permission to use, copy, modify, distribute, and sell this software and its
 
5
 * documentation for any purpose is hereby granted without fee, provided that
 
6
 * the above copyright notice appear in all copies and that both that
 
7
 * copyright notice and this permission notice appear in supporting
 
8
 * documentation.  No representations are made about the suitability of this
 
9
 * software for any purpose.  It is provided "as is" without express or
 
10
 * implied warranty.
 
11
 */
 
12
 
 
13
// Module API:
 
14
//  setup (canvas_element,              initialization
 
15
//         background_element,
 
16
//         fonts)
 
17
//  show ()                             start animation timers
 
18
//  hide ()                             stop animation timers
 
19
//  destroy ()                          about to exit
 
20
//  changeSettings (settings)           change how clock is displayed
 
21
//
 
22
//  The settings object contains:
 
23
//
 
24
//    width             size of clock display area
 
25
//    height            size of clock display area
 
26
//    orientation       'up' | 'left' | 'right' | 'down'
 
27
//    time_mode         'HHMMSS' | 'HHMM' | 'SS'
 
28
//    date_mode         'MMDDYY' | 'DDMMYY' | 'YYMMDD'
 
29
//    twelve_hour_p     boolean, whether to display 12 or 24-hour time
 
30
//    show_date_p       boolean, whether to display date instead of time
 
31
//    fps               integer (frames per second)
 
32
//    cps               integer (color changes per second)
 
33
//    vp_scaling_p      whether canvas scaling works for antialiasing
 
34
 
 
35
 
 
36
function DaliClock() {
 
37
}
 
38
 
 
39
DaliClock.prototype.setup = function (canvas_element, background_element,
 
40
                                      fonts) {
 
41
 
 
42
  this.canvas  = canvas_element;
 
43
  this.clockbg = background_element;
 
44
  this.fonts   = fonts;
 
45
  this.shown_p = false;
 
46
 
 
47
  this.fg_hsv = [200, 0.4, 1.0];
 
48
  this.bg_hsv = [128, 1.0, 0.4];
 
49
 
 
50
  this.fg_hsv[0] += Math.floor(Math.random()*360);
 
51
  this.bg_hsv[0] += Math.floor(Math.random()*360);
 
52
 
 
53
  this.changeSettings(undefined);
 
54
}
 
55
 
 
56
 
 
57
// Change display settings at next second-tick.
 
58
//
 
59
DaliClock.prototype.changeSettings = function(settings) {
 
60
 
 
61
  var copy = new Object;
 
62
  for (var e in settings) { copy[e] = settings[e]; }
 
63
  this.new_settings = copy;
 
64
 
 
65
  // We can process these immediately
 
66
  if (settings) {
 
67
    this.clock_freq = settings.fps ? Math.round (1000 / settings.fps) : 0;
 
68
    this.color_freq = settings.cps ? Math.round (1000 / settings.cps) : 0;
 
69
  }
 
70
 
 
71
  if (this.clock_freq <= 0) this.clock_freq = 1;
 
72
 
 
73
  // If the clock is hidden, we can process everything immediately.
 
74
  if (!this.shown_p) this.settings_changed();
 
75
}
 
76
 
 
77
 
 
78
// Called at the start of each sequence if the new_settings object exists.
 
79
// All settings changes are delayed until the second-tick.
 
80
//
 
81
DaliClock.prototype.settings_changed = function() {
 
82
 
 
83
  // Changes to some settings require tearing down and rebuilding
 
84
  // the clock.  Changes to others can be animated normally.
 
85
  //
 
86
  var reset_p =
 
87
    (this.settings              == undefined ||
 
88
     this.settings.width        != this.new_settings.width  ||
 
89
     this.settings.height       != this.new_settings.height ||
 
90
     this.settings.time_mode    != this.new_settings.time_mode ||
 
91
     this.settings.orientation  != this.new_settings.orientation ||
 
92
     this.settings.vp_scaling_p != this.new_settings.vp_scaling_p);
 
93
 
 
94
  this.settings = this.new_settings;
 
95
  this.new_settings = undefined;
 
96
 
 
97
  if (reset_p) this.clock_reset();
 
98
}
 
99
 
 
100
 
 
101
// For setup tasks that have to happen each time the window becomes visible.
 
102
//
 
103
DaliClock.prototype.show = function() {
 
104
 
 
105
  if (this.shown_p) return;
 
106
  this.shown_p = true;
 
107
 
 
108
  // Start the color timer.
 
109
  this.color_timer_fn = this.color_timer.bind(this);
 
110
  this.color_timer_fn();
 
111
 
 
112
  // Start the clock timer.
 
113
  this.clock_timer_fn = this.clock_timer.bind(this);
 
114
  this.clock_timer_fn();
 
115
 
 
116
 
 
117
}
 
118
 
 
119
 
 
120
// Tasks that have to happen each time the window is hidden.
 
121
//
 
122
DaliClock.prototype.hide = function() {
 
123
 
 
124
  if (!this.shown_p) return;
 
125
  this.shown_p = false;
 
126
 
 
127
  if (this.clock_timer_id) {
 
128
    window.clearTimeout (this.clock_timer_id);
 
129
    this.clock_timer_id = undefined;
 
130
  }
 
131
  if (this.color_timer_id) {
 
132
    window.clearTimeout (this.color_timer_id);
 
133
    this.color_timer_id = undefined;
 
134
  }
 
135
}
 
136
 
 
137
 
 
138
// About to exit.
 
139
//
 
140
DaliClock.prototype.cleanup = function() {
 
141
  this.hide();
 
142
}
 
143
 
 
144
 
 
145
// Reset the animation when the settings (number of digits, orientation)
 
146
// has changed.  We have to start over since the resolution is different.
 
147
//
 
148
DaliClock.prototype.clock_reset = function() {
 
149
 
 
150
  this.pick_font_size();
 
151
 
 
152
  if (! this.font.empty_frame) {
 
153
    this.font.empty_frame = this.make_empty_frame (this.font, false);
 
154
    this.font.empty_colon = this.make_empty_frame (this.font, true);
 
155
  }
 
156
 
 
157
  this.orig_frames    = new Array(8);  // what was there
 
158
  this.current_frames = new Array(8);  // current intermediate animation
 
159
  this.target_frames  = new Array(8);  // where we are going
 
160
  this.target_digits  = new Array(8);  // where we are going
 
161
 
 
162
  for (var i = 0; i < this.current_frames.length; i++) {
 
163
    var colonic_p = (i == 2 || i == 5);
 
164
    var empty = (colonic_p ? this.font.empty_colon : this.font.empty_frame);
 
165
    this.orig_frames[i]    = empty;
 
166
    this.target_frames[i]  = empty;
 
167
    this.current_frames[i] = this.copy_frame (empty);
 
168
  }
 
169
 
 
170
 
 
171
  // Set the CSS orientation of the canvas based on the current orientation.
 
172
  // Webkit uses "webkitTransform".  Firefox 3.5 uses "MozTransform".
 
173
  // Maybe someday it will be just "transform".  We set them all...
 
174
  //
 
175
  var tr;
 
176
  switch (this.settings.orientation) {
 
177
    case 'left':  tr = 'rotate(90deg)' ; break;
 
178
    case 'right': tr = 'rotate(-90deg)'; break;
 
179
    case 'down':  tr = 'rotate(180deg)'; break;
 
180
    default:      tr = ''; break;
 
181
  }
 
182
  this.canvas.style.transform       = tr;
 
183
  this.canvas.style.webkitTransform = tr;
 
184
  this.canvas.style.MozTransform    = tr;
 
185
 
 
186
 
 
187
  // And now set the CSS position and size of the canvas
 
188
  // (not the same thing as size of the canvas's frame buffer).
 
189
  //
 
190
  var width  = this.canvas.width;   // size of the framebuffer
 
191
  var height = this.canvas.height;
 
192
  var nn, cc;
 
193
 
 
194
  switch (this.settings.time_mode) {
 
195
    case 'SS':   nn = 2; cc = 0; break;
 
196
    case 'HHMM': nn = 4; cc = 1; break;
 
197
    default:     nn = 6; cc = 2; break;
 
198
  }
 
199
 
 
200
  this.displayed_digits = nn + cc;
 
201
 
 
202
  if (this.settings.vp_scaling_p) {   // was doubled, for anti-aliasing
 
203
    // width  /= 2;
 
204
    // height /= 2;
 
205
    var r  = height / width;
 
206
    width  = Math.floor(this.settings.width);
 
207
    height = Math.floor(width * r);
 
208
  }
 
209
 
 
210
  x = (this.settings.width  - width)  / 2;
 
211
  y = (this.settings.height - height) / 2;
 
212
 
 
213
  this.ctx = this.canvas.getContext("2d");
 
214
 
 
215
  this.canvas.style.left   = x + 'px';
 
216
  this.canvas.style.top    = y + 'px';
 
217
  this.canvas.style.width  = width  + 'px';
 
218
  this.canvas.style.height = height + 'px';
 
219
 
 
220
}
 
221
 
 
222
 
 
223
// Gets the current wall clock and formats the display accordingly.
 
224
//
 
225
DaliClock.prototype.fill_target_digits = function(date) {
 
226
 
 
227
  var h = date.getHours();
 
228
  var m = date.getMinutes();
 
229
  var s = date.getSeconds();
 
230
  var D = date.getDate();
 
231
  var M = date.getMonth() + 1;
 
232
  var Y = date.getFullYear() % 100;
 
233
 
 
234
  if (this.settings.twelve_hour_p) {
 
235
    if (h > 12) { h -= 12; }
 
236
    else if (h == 0) { h = 12; }
 
237
  }
 
238
 
 
239
  for (var i = 0; i < this.target_digits.length; i++) {
 
240
    this.target_digits[i] = undefined;
 
241
  }
 
242
 
 
243
  if (this.settings.debug_digit != undefined) {
 
244
    if (this.settings.debug_digit < 0 ||
 
245
        this.settings.debug_digit > 11)
 
246
      this.settings.debug_digit = undefined;
 
247
    this.target_digits[0] = this.target_digits[1] = 
 
248
    this.target_digits[3] = this.target_digits[4] = 
 
249
    this.target_digits[6] = this.target_digits[7] = this.settings.debug_digit;
 
250
    this.settings.debug_digit = undefined;
 
251
 
 
252
  } else if (!this.settings.show_date_p) {
 
253
 
 
254
    switch (this.settings.time_mode) {
 
255
      case 'SS':
 
256
        this.target_digits[0] = Math.floor(s / 10);
 
257
        this.target_digits[1] =           (s % 10);
 
258
        break;
 
259
      case 'HHMM':
 
260
        this.target_digits[0] = Math.floor(h / 10);
 
261
        this.target_digits[1] =           (h % 10);
 
262
        this.target_digits[2] =                10;  // colon
 
263
        this.target_digits[3] = Math.floor(m / 10);
 
264
        this.target_digits[4] =           (m % 10);
 
265
        if (this.settings.twelve_hour_p && this.target_digits[0] == 0) {
 
266
          this.target_digits[0] = undefined;
 
267
        }
 
268
        break;
 
269
      default:
 
270
        this.target_digits[0] = Math.floor(h / 10);
 
271
        this.target_digits[1] =           (h % 10);
 
272
        this.target_digits[2] =                10;  // colon
 
273
        this.target_digits[3] = Math.floor(m / 10);
 
274
        this.target_digits[4] =           (m % 10);
 
275
        this.target_digits[5] =                10;  // colon
 
276
        this.target_digits[6] = Math.floor(s / 10);
 
277
        this.target_digits[7] =           (s % 10);
 
278
        if (this.settings.twelve_hour_p && this.target_digits[0] == 0) {
 
279
          this.target_digits[0] = undefined;
 
280
        }
 
281
        break;
 
282
    }
 
283
  } else {  // date mode
 
284
 
 
285
    switch (this.settings.date_mode) {
 
286
      case 'MMDDYY':
 
287
        switch (this.settings.time_mode) {
 
288
          case 'SS':
 
289
            this.target_digits[0] = Math.floor(D / 10);
 
290
            this.target_digits[1] =           (D % 10);
 
291
            break;
 
292
          case 'HHMM':
 
293
            this.target_digits[0] = Math.floor(M / 10);
 
294
            this.target_digits[1] =           (M % 10);
 
295
            this.target_digits[2] =                11;  // dash
 
296
            this.target_digits[3] = Math.floor(D / 10);
 
297
            this.target_digits[4] =           (D % 10);
 
298
            break;
 
299
          default:  // HHMMSS
 
300
            this.target_digits[0] = Math.floor(M / 10);
 
301
            this.target_digits[1] =           (M % 10);
 
302
            this.target_digits[2] =                11;  // dash
 
303
            this.target_digits[3] = Math.floor(D / 10);
 
304
            this.target_digits[4] =           (D % 10);
 
305
            this.target_digits[5] =                11;  // dash
 
306
            this.target_digits[6] = Math.floor(Y / 10);
 
307
            this.target_digits[7] =           (Y % 10);
 
308
            break;
 
309
        }
 
310
        break;
 
311
      case 'DDMMYY':
 
312
        switch (this.settings.time_mode) {
 
313
          case 'SS':
 
314
            this.target_digits[0] = Math.floor(D / 10);
 
315
            this.target_digits[1] =           (D % 10);
 
316
            break;
 
317
          case 'HHMM':
 
318
            this.target_digits[0] = Math.floor(D / 10);
 
319
            this.target_digits[1] =           (D % 10);
 
320
            this.target_digits[2] =                11;  // dash
 
321
            this.target_digits[3] = Math.floor(M / 10);
 
322
            this.target_digits[4] =           (M % 10);
 
323
            break;
 
324
          default:  // HHMMSS
 
325
            this.target_digits[0] = Math.floor(D / 10);
 
326
            this.target_digits[1] =           (D % 10);
 
327
            this.target_digits[2] =                11;  // dash
 
328
            this.target_digits[3] = Math.floor(M / 10);
 
329
            this.target_digits[4] =           (M % 10);
 
330
            this.target_digits[5] =                11;  // dash
 
331
            this.target_digits[6] = Math.floor(Y / 10);
 
332
            this.target_digits[7] =           (Y % 10);
 
333
            break;
 
334
        }
 
335
        break;
 
336
      default:
 
337
        switch (this.settings.time_mode) {
 
338
          case 'SS':
 
339
            this.target_digits[0] = Math.floor(D / 10);
 
340
            this.target_digits[1] =           (D % 10);
 
341
            break;
 
342
          case 'HHMM':
 
343
            this.target_digits[0] = Math.floor(M / 10);
 
344
            this.target_digits[1] =           (M % 10);
 
345
            this.target_digits[2] =                11;  // dash
 
346
            this.target_digits[3] = Math.floor(D / 10);
 
347
            this.target_digits[4] =           (D % 10);
 
348
            break;
 
349
          default:  // HHMMSS
 
350
            this.target_digits[0] = Math.floor(Y / 10);
 
351
            this.target_digits[1] =           (Y % 10);
 
352
            this.target_digits[2] =                11;  // dash
 
353
            this.target_digits[3] = Math.floor(M / 10);
 
354
            this.target_digits[4] =           (M % 10);
 
355
            this.target_digits[5] =                11;  // dash
 
356
            this.target_digits[6] = Math.floor(D / 10);
 
357
            this.target_digits[7] =           (D % 10);
 
358
            break;
 
359
        }
 
360
        break;
 
361
    }
 
362
  }
 
363
}
 
364
 
 
365
 
 
366
// Find the largest font that fits in the canvas given the current settings
 
367
// (number of digits and orientation).
 
368
//
 
369
DaliClock.prototype.pick_font_size = function() {
 
370
 
 
371
  var nn, cc;
 
372
 
 
373
  switch (this.settings.time_mode) {
 
374
    case 'SS':   nn = 2; cc = 0; break;
 
375
    case 'HHMM': nn = 4; cc = 1; break;
 
376
    default:     nn = 6; cc = 2; break;
 
377
  }
 
378
 
 
379
  var width  = this.settings.width;
 
380
  var height = this.settings.height;
 
381
 
 
382
  if (this.settings.vp_scaling_p) {   // double it, for anti-aliasing
 
383
    width  *= 2;
 
384
    height *= 2;
 
385
  }
 
386
 
 
387
  if (this.settings.orientation == 'left' || 
 
388
      this.settings.orientation == 'right') {
 
389
    var swap = width; width = height; height = swap;
 
390
  }
 
391
 
 
392
  for (var i = this.fonts.length-1; i >= 0; i--) {
 
393
    var font = this.fonts[i];
 
394
    var w = (font.char_width * nn) + (font.colon_width * cc);
 
395
    var h = font.char_height;
 
396
 
 
397
    if ((w <= width && h <= height) ||
 
398
        i == 0) {
 
399
      this.font          = font;
 
400
      this.canvas.width  = w;
 
401
      this.canvas.height = h;
 
402
      return;
 
403
    }
 
404
  }
 
405
}
 
406
 
 
407
 
 
408
DaliClock.prototype.make_empty_frame = function(font, colonic_p) {
 
409
  var cw = (colonic_p ? font.colon_width : font.char_width);
 
410
  var ch = font.char_height;
 
411
  var mid = Math.round(cw / 2);
 
412
  var frame = new Array(ch);
 
413
  for (var y = 0; y < ch; y++) {
 
414
    var line, seg;
 
415
    line = frame[y] = new Array(1);
 
416
    seg = line[0] = new Array(2);
 
417
    seg[0] = seg[1] = mid;
 
418
  }
 
419
  return frame;
 
420
}
 
421
 
 
422
 
 
423
DaliClock.prototype.copy_frame = function(oframe) {
 
424
 
 
425
  if (oframe == undefined) { return oframe; }
 
426
  var nframe = oframe.slice();   // copy array of lines
 
427
  var ch = nframe.length;
 
428
  for (var y = 0; y < ch; y++) {
 
429
    if (nframe[y]) { nframe[y] = nframe[y].slice(); }  // copy array of segs
 
430
    var segs = nframe[y].length;
 
431
    for (var x = 0; x < segs; x++) {
 
432
      if (nframe[y][x]) { nframe[y][x] = nframe[y][x].slice(); }  // copy segs
 
433
    }
 
434
    segs = nframe[y].length;
 
435
  }
 
436
  return nframe;
 
437
}
 
438
 
 
439
 
 
440
DaliClock.prototype.draw_frame = function(frame, x, y) {
 
441
 
 
442
  var ch = this.font.char_height;
 
443
  for (var py = 0; py < ch; py++)
 
444
    {
 
445
      var line  = frame[py];
 
446
      var nsegs = line.length;
 
447
      for (var px = 0; px < nsegs; px++)
 
448
        {
 
449
          var seg = line[px];
 
450
          this.ctx.fillRect (x + seg[0], y + py,
 
451
                             seg[1] - seg[0], 1);
 
452
        }
 
453
    }
 
454
}
 
455
 
 
456
 
 
457
// The second has ticked: we need a new set of digits to march toward.
 
458
//
 
459
DaliClock.prototype.start_sequence = function(date) {
 
460
 
 
461
  if (this.new_settings)
 
462
    this.settings_changed();
 
463
 
 
464
  // Copy the (old) current_frames into the (new) orig_frames,
 
465
  // since that's what's on the screen now.
 
466
  //
 
467
  for (var i = 0; i < this.current_frames.length; i++) {
 
468
    this.orig_frames[i] = this.current_frames[i];
 
469
  }
 
470
 
 
471
  // generate new target_digits
 
472
  this.fill_target_digits (date);
 
473
 
 
474
  // Fill the (new) target_frames from the (new) target_digits.
 
475
  //
 
476
  for (var i = 0; i < this.target_frames.length; i++) {
 
477
    var colonic_p = (i == 2 || i == 5);
 
478
    var empty = (colonic_p ? this.font.empty_colon : this.font.empty_frame);
 
479
    var frame = (this.target_digits[i] == undefined
 
480
                 ? empty
 
481
                 : this.font.segments[this.target_digits[i]]);
 
482
    this.target_frames[i] = frame;
 
483
  }
 
484
 
 
485
  this.draw_clock ();
 
486
}
 
487
 
 
488
 
 
489
DaliClock.prototype.one_step = function(orig, curr, target, msecs) {
 
490
 
 
491
  var ch = this.font.char_height;
 
492
  var frac = msecs / 1000.0;
 
493
 
 
494
  for (var i = 0; i < ch; i++) {
 
495
    var oline = orig[i];
 
496
    var cline = curr[i];
 
497
    var tline = target[i];
 
498
    var osegs = oline.length;
 
499
    var tsegs = tline.length;
 
500
    var segs = (osegs > tsegs ? osegs : tsegs);
 
501
 
 
502
    // orig and target might have different numbers of segments.
 
503
    // current ends up with the maximal number.
 
504
 
 
505
    for (var j = 0; j < segs; j++) {
 
506
      var oseg = oline[j] || oline[0];
 
507
      var cseg = cline[j];
 
508
      var tseg = tline[j] || tline[0];
 
509
 
 
510
      if (! cseg) { cseg = cline[j] = new Array(2); }
 
511
 
 
512
      cseg[0] = oseg[0] + Math.round (frac * (tseg[0] - oseg[0]));
 
513
      cseg[1] = oseg[1] + Math.round (frac * (tseg[1] - oseg[1]));
 
514
    }
 
515
  }
 
516
}
 
517
 
 
518
 
 
519
// Compute the current animation state of each digit into target_frames
 
520
// according to our current position within the current wall-clock second.
 
521
//
 
522
DaliClock.prototype.tick_sequence = function() {
 
523
 
 
524
  var now   = new Date();
 
525
  var ctime = now.getTime();
 
526
  var secs  = Math.floor(ctime/1000);
 
527
  var msecs = ctime - (secs*1000);    // msec position within this second
 
528
 
 
529
  if (! this.last_secs) {
 
530
    this.last_secs = secs;   // fading in!
 
531
  } else if (secs != this.last_secs) {
 
532
    // End of the animation sequence; fill target_frames with the
 
533
    // digits of the current time.
 
534
    this.start_sequence (now);
 
535
    this.last_secs = secs;
 
536
  }
 
537
 
 
538
  // Linger for about 1/10th second at the end of each cycle.
 
539
  msecs *= 1.2;
 
540
  if (msecs > 1000) msecs = 1000;
 
541
 
 
542
  // Construct current_frames by interpolating between
 
543
  // orig_frames and target_frames.
 
544
  //
 
545
  for (var i = 0; i < this.orig_frames.length; i++) {
 
546
    this.one_step (this.orig_frames[i],
 
547
                   this.current_frames[i],
 
548
                   this.target_frames[i],
 
549
                   msecs);
 
550
  }
 
551
}
 
552
 
 
553
 
 
554
// Render the current animation state of each digit.
 
555
//
 
556
DaliClock.prototype.draw_clock = function() {
 
557
 
 
558
  var x = 0;
 
559
  var y = 0;
 
560
  this.ctx.clearRect (0, 0, this.canvas.width, this.canvas.height);
 
561
 
 
562
  for (var i = 0; i < this.displayed_digits; i++) {
 
563
    this.draw_frame (this.current_frames[i], x, y);
 
564
    var colonic_p = (i == 2 || i == 5);
 
565
    x += (colonic_p ? this.font.colon_width : this.font.char_width);
 
566
  }
 
567
}
 
568
 
 
569
 
 
570
DaliClock.prototype.clock_timer = function() {
 
571
 
 
572
  this.tick_sequence ();
 
573
  this.draw_clock ();
 
574
 
 
575
  // Re-trigger our timer.
 
576
  this.clock_timer_id = window.setTimeout (this.clock_timer_fn, 
 
577
                                           this.clock_freq);
 
578
}
 
579
 
 
580
 
 
581
DaliClock.prototype.tick_colors = function() {
 
582
 
 
583
  this.ctx.fillStyle = this.hsv_to_rgb (this.fg_hsv[0],
 
584
                                        this.fg_hsv[1],
 
585
                                        this.fg_hsv[2]);
 
586
  this.clockbg.style.backgroundColor = this.hsv_to_rgb (this.bg_hsv[0],
 
587
                                                        this.bg_hsv[1],
 
588
                                                        this.bg_hsv[2]);
 
589
 
 
590
  this.fg_hsv[0] += 1;
 
591
  if (this.fg_hsv[0] >= 360) { this.fg_hsv[0] -= 360; }
 
592
 
 
593
  this.bg_hsv[0] += 0.91;
 
594
  if (this.bg_hsv[0] >= 360) { this.bg_hsv[0] -= 360; }
 
595
}
 
596
 
 
597
 
 
598
DaliClock.prototype.color_timer = function() {
 
599
 
 
600
  // cps == 0 means don't cycle colors. but the timer still goes off
 
601
  // at least once a second in case cps has changed.
 
602
 
 
603
  var when = this.color_freq;
 
604
  if (when > 0)
 
605
    this.tick_colors();
 
606
  else
 
607
    when = 2000;
 
608
 
 
609
  this.color_timer_id = window.setTimeout(this.color_timer_fn, when);
 
610
}
 
611
 
 
612
 
 
613
// H is in the range 0 - 360;
 
614
// S and V are in the range 0.0 - 1.0.
 
615
// Returns string "rgb(255,255,255)"
 
616
//
 
617
DaliClock.prototype.hsv_to_rgb = function(h,s,v) {
 
618
 
 
619
  if (s < 0) s = 0;
 
620
  if (v < 0) v = 0;
 
621
  if (s > 1) s = 1;
 
622
  if (v > 1) v = 1;
 
623
 
 
624
  var S = s; 
 
625
  var V = v;
 
626
  var H = (h % 360) / 60.0;
 
627
  var i = Math.floor(H);
 
628
  var f = H - i;
 
629
  var p1 = V * (1 - S);
 
630
  var p2 = V * (1 - (S * f));
 
631
  var p3 = V * (1 - (S * (1 - f)));
 
632
  if      (i == 0) { R = V;  G = p3; B = p1; }
 
633
  else if (i == 1) { R = p2; G = V;  B = p1; }
 
634
  else if (i == 2) { R = p1; G = V;  B = p3; }
 
635
  else if (i == 3) { R = p1; G = p2; B = V;  }
 
636
  else if (i == 4) { R = p3; G = p1; B = V;  }
 
637
  else             { R = V;  G = p1; B = p2; }
 
638
 
 
639
  return ('rgb(' +
 
640
          Math.floor(R * 255) + ',' +
 
641
          Math.floor(G * 255) + ',' +
 
642
          Math.floor(B * 255) + ')');
 
643
}
 
644
 
 
645
 
 
646
DaliClock.prototype.LOG = function() {
 
647
  var logger = document.getElementById("log");
 
648
  if (logger) {
 
649
    var args = DaliClock.prototype.LOG.arguments;
 
650
    logger.firstChild.nodeValue = '';
 
651
    for (var i = 0; i < args.length; i++) {
 
652
      logger.firstChild.nodeValue += args[i] + ' ';
 
653
    }
 
654
  }
 
655
}
 
656
 
 
657
 
 
658
DaliClock.prototype.LOG2 = function() {
 
659
  var logger = document.getElementById("log");
 
660
  if (logger) {
 
661
    var args = DaliClock.prototype.LOG2.arguments;
 
662
    //logger.firstChild.nodeValue = '';
 
663
    for (var i = 0; i < args.length; i++) {
 
664
      logger.firstChild.nodeValue += args[i] + ' ';
 
665
    }
 
666
  }
 
667
}