Canvas с нуля. Аналоговые часы на JS

Canvas появился в html5, он позволяет рисовать любую графику в окне. Создаётся он так:
1
<canvas id='canvas' width="300px" height="200px"></div>
В таком окне можно рисовать линии (как прямые, так и линии безье), точки, окружности и т.д. С помощью canvas можно рисовать изображения поворачивая их на произвольный градус. В canvas возможно отображение 3D-объектов. Используемые функции: document.getElementById("canvas") - получаем DOM-элемент холста(canvas). canvas.getContext("2d") - особенность canvas. Перед тем, как начать рисование на хосте, программист должен получить его контекст. Рисование будет производится с помощью контекста. ctx.beginPath(), ctx.closePath() - начало и окончание рисования замкнутой фигуры. Если начальная и конечная точка не будет замкнута, closePath() постарается завершить фигуру самостоятельно. ctx.moveTo(200,130); - указание точки откуда будет производиться рисование линии. ctx.lineTo(200,130); - указание точки куда будет производиться рисование линии. ctx.arc(150,102,27,0,2*Math.PI); - самая сложная в следующем примере функция. Рисование окружности с центром в точке (150px,102px) и радиусом равным 27px. Нулевые координаты холста находятся в левом-верхнем углу (точка (0,0)). ctx.stroke() - заставить контекст отрисовать указанную фигуру без заливки (если Вы хотите её залить, то используйте ctx.fill()). Пример рисования в canvas:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<canvas width="300px" height="200px" id="canvas"></canvas>
<script>
var ctx = document.getElementById("canvas").getContext("2d");
var lines = [
    {x: 100, y: 130},
    {x: 150, y: 50},
    {x: 200, y: 130},
    {x: 100, y: 130},
    {x: 150, y: 130},
    {x: 150, y: 50},
  ],
  line = lines.shift();
 
ctx.beginPath();
do {
  ctx.moveTo(line.x, line.y);
  line = lines.shift();
  ctx.lineTo(line.x, line.y);
} while (lines.length);
 
ctx.stroke();
ctx.closePath();
 
ctx.beginPath();
ctx.arc(150, 102, 27, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
</script>
Далее следует пример интереснее. Функции почти все знакомы, кроме: canvas.height, canvas.width - получение высоты и ширины холста. new Date().getSeconds(), new Date().getMinutes(), new Date().getHours() - получение времени в секундах (0-59), минутах (0-59) и часах (0-23). ctx.clearRect (0, 0, width, height) - очистка холста. setInterval(alarm,1000) - вызов функции alarm каждую секунду. Пример аналоговых часов:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<canvas width="300" height="200" id="alarm"></canvas>
<script>
//Берём у нашего Canvas контекст (с его помощью и будем рисовать)
var ctx = document.getElementById("alarm").getContext("2d");
 
//Создание таймера, вызывающего всю перерисовку
var interval = setInterval(tick, 1000);
 
//функция перерисовки Context'а
//вызывается каждую секунду
function tick() {
  var radius = ctx.canvas.height / 2 - 5,
    date = getSecondsObject(new Date),
    radians = secondsObjectToRadians(date),
    lines = radiansToRadialLines(radians, radius);
 
  //Функция очистки Context
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
 
  drawBigCircle(radius);
  draw12Points(radius);
  drawArrows(lines);
}
 
function radiansToRadialLines(obj, radius) {
  return [
    { angle: obj.secondsAngle, width: 1, radius: radius * 0.9  },
    { angle: obj.minutesAngle, width: 2, radius: radius * 0.75 },
    { angle: obj.hoursAngle,   width: 3, radius: radius * 0.6  }
  ];
}
 
function secondsObjectToRadians(obj) {
  //Получаем значения углов стрелок в радианах
  var normalize = function (value, min, max) { return (value - min) / (max - min); };
  var normalizedToAngle = function (value) { return value * Math.PI * 2 - Math.PI / 2 };
 
  return {
    secondsAngle: normalizedToAngle(normalize(obj.seconds, 0, 60)),
    minutesAngle: normalizedToAngle(normalize(obj.minutes, 0, 60 * 60)),
    hoursAngle: normalizedToAngle(normalize(obj.hours, 0, 60 * 60 * 24))
  };
}
 
//Перевод даты в секунды
function getSecondsObject(date) {
  var hours = date.getHours() * 60 * 60;
  var minutes = date.getMinutes() * 60;
  var seconds = date.getSeconds();
 
  return {
    seconds:  seconds ,
    minutes:  minutes + seconds,
    hours:  hours + minutes + seconds
  };
}
 
function drawBigCircle(radius) {
  //Обводится по контуру
  stroke(function () {
    ctx.lineWidth = 1;
    //круг циферблата
    ctx.arc(ctx.canvas.width / 2, ctx.canvas.height / 2, radius, 0, 2 * Math.PI);
  });
}
 
function draw12Points(radius) {
  //Рисует 12 кружков, соответствующих часам
  //2 * Math.PI / 12 - это 1/12 полного круга часов
  for (var i = 0; i <= Math.PI * 2; i += 2 * Math.PI / 12) {
    fill(function () {
      ctx.fillStyle = "red";
      ctx.arc(
        ctx.canvas.width / 2 + radius * Math.cos(i),
        ctx.canvas.height / 2 + radius * Math.sin(i),
        3, 0, 2 * Math.PI);
    });
  }
}
 
function drawArrows(lines) {
  function drawLine(angle, radius, width) {
    stroke(function () {
      var x0 = ctx.canvas.width / 2, y0 = ctx.canvas.height / 2;
      ctx.lineWidth = width;
      ctx.moveTo(x0, y0);
      ctx.lineTo(x0 + radius * Math.cos(angle), y0 + radius * Math.sin(angle));
    });
  };
  //Рисование стрелок часов
  lines.forEach(function (line) {
    drawLine(line.angle, line.radius, line.width);
  });
}
 
function stroke(fn, params) {
  ctx.beginPath();
  fn(params);
  ctx.stroke();
  ctx.closePath();
}
 
function fill(fn, params) {
  ctx.beginPath();
  fn(params);
  ctx.fill();
  ctx.closePath();
}
</script>
Спасибо за внимание.
Если статья Вам показалась незаконченной или Вы знаете как её улучшить, пожалуйста сообщите мне e@gohtml.ru