init({ range: [[-4, 4], [-4, 4]], scale: 45 });
var clockRadius = 3.75;
var minuteSnapPoints = 12;
var hourSnapPoints = 12 * 60 / MINUTE_INCREMENT;
var outerPointRadius = clockRadius * 1.01;
var minuteRadius = clockRadius * 0.6;
var hourRadius = clockRadius * 0.45;
minuteStartAngle = 90;
hourStartAngle = 60;
minuteSnapDegrees = 360 / minuteSnapPoints;
hourSnapDegrees = 360 / hourSnapPoints;
var clock = addAnalogClock({ radius: clockRadius, minuteTicks: 60 });
clock.draw();
addMouseLayer();
function movePartnerPoint(options) {
var x = options.x;
var y = options.y;
var point = options.point;
var outerPoint = options.outerPoint;
var isOuterPoint = options.isOuterPoint;
var ratio = outerPoint.constraints.fixedDistance.dist / point.constraints.fixedDistance.dist;
if (isOuterPoint) {
ratio = 1 / ratio;
point.setCoord([x * ratio , y * ratio]);
outerPoint.setCoord([x, y]);
} else {
point.setCoord([x, y]);
outerPoint.setCoord([x * ratio, y * ratio]);
}
point.updateLineEnds();
return true;
}
minutePoint = addMovablePoint({
coord: polar( minuteRadius, minuteStartAngle ),
constraints: {
fixedDistance: {
dist: minuteRadius,
point: [0, 0],
snapPoints: 12
}
},
onMove: function(x, y) {
return movePartnerPoint({ x: x, y: y, point: this, outerPoint: outerMinutePoint, isOuterPoint: false });
},
normalStyle: {
fill: ORANGE,
stroke: ORANGE
},
highlightStyle: {
fill: ORANGE,
stroke: ORANGE
}
});
outerMinutePoint = addMovablePoint({
coord: polar(outerPointRadius, minuteStartAngle),
constraints: {
fixedDistance: {
dist: outerPointRadius,
point: [0, 0],
snapPoints: 12
}
},
onMove: function(x, y) {
return movePartnerPoint({ x: x, y: y, point: minutePoint, outerPoint: this, isOuterPoint: true });
},
normalStyle: {
fill: ORANGE,
stroke: ORANGE
},
highlightStyle: {
fill: ORANGE,
stroke: ORANGE
}
});
hourPoint = addMovablePoint({
coord: polar(hourRadius, hourStartAngle),
constraints: {
fixedDistance: {
dist: hourRadius,
point: [0, 0],
snapPoints: hourSnapPoints
}
},
onMove: function(x, y) {
return movePartnerPoint({ x: x, y: y, point: this, outerPoint: outerHourPoint, isOuterPoint: false });
},
normalStyle: {
fill: BLUE,
stroke: BLUE
},
highlightStyle: {
fill: BLUE,
stroke: BLUE
}
});
outerHourPoint = addMovablePoint({
coord: polar(outerPointRadius, hourStartAngle),
constraints: {
fixedDistance: {
dist: outerPointRadius,
point: [0, 0],
snapPoints: hourSnapPoints
}
},
onMove: function(x, y) {
return movePartnerPoint({ x: x, y: y, point: hourPoint, outerPoint: this, isOuterPoint: true });
},
normalStyle: {
fill: BLUE,
stroke: BLUE
},
highlightStyle: {
fill: BLUE,
stroke: BLUE
}
});
minuteHand = addMovableLineSegment({
pointA: minutePoint,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: ORANGE,
"stroke-width": 10
}
});
hourHand = addMovableLineSegment({
pointA: hourPoint,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: BLUE,
"stroke-width": 10
}
});
centerPoint = addMovablePoint({
coord: [0, 0],
constraints: {
fixed: true
},
normalStyle: {
fill: "#fff",
stroke: "#000",
"stroke-width": 2
}
});
correctMinuteAngle = timeToDegrees(MINUTE);
correctHourAngle = timeToDegrees(5 * (HOUR + MINUTE / 60));
correctMinuteAngle = roundToNearest(minuteSnapDegrees, correctMinuteAngle);
correctHourAngle = roundToNearest(hourSnapDegrees, correctHourAngle);
Drag the two hands so the clock reads HOUR:NICE_MINUTE.
[minutePoint.coord, hourPoint.coord]
var minuteAngle = cartToPolar(guess[0])[1];
var hourAngle = cartToPolar(guess[1])[1];
minuteAngle = roundToNearest(minuteSnapDegrees, minuteAngle);
hourAngle = roundToNearest(hourSnapDegrees, hourAngle);
// if hands have not been moved, return `""`
if (minuteAngle === minuteStartAngle && hourAngle === hourStartAngle) {
return "";
}
if ((minuteAngle !== correctMinuteAngle) || (hourAngle !== correctHourAngle)) {
if ((minuteAngle === correctHourAngle) && (hourAngle === correctMinuteAngle)) {
return $._("Remember the hour hand is the short hand and the minute hand is the long hand");
}
else if ((minuteAngle === correctMinuteAngle) && (hourAngle !== correctHourAngle)
&& (hourAngle === roundToNearest(hourSnapDegrees, timeToDegrees(5 * HOUR)))) {
return $._("Remember the hour hand needs to move over the course of the hour");
}
return false;
}
return true;
minutePoint.moveTo(guess[0][0], guess[0][1], true);
hourPoint.moveTo(guess[1][0], guess[1][1], true);
The hour hand is the short
blue bar and the
minute hand is the long
orange bar.
The number after the \Large{:} symbol represents the number of minutes past
the hour. So TIME represents MINUTE
minutes past hour HOUR.
First, let's set the minute hand.
Each long tick mark is an increment of 5 minutes, because
60 minutes / 12 tick marks = 5 minutes per tick mark.
Since we are MINUTE
minutes past the hour, the minute hand should
be at the mark numbered
12, which is
the first tick mark on the clock and represents
0 minutes past the hour.
Since we are MINUTE
minutes past the hour, and there are 5 minutes
per tick mark, the minute hand should be at the
mark numbered
fraction(MINUTE, 5) = MINUTE/5
Next, let's set the hour hand.
The 12 long tick marks correspond to the hours in the day (assuming AM/PM time).
If it is 0 minutes past the hour, the hour hand belongs directly on the
corresponding hour mark. But, over the hour, the hour hand must travel so it reaches
the next hour by the time the hour changes.
Since it's 0 minutes past the hour, the hour hand should be right on the
HOUR hour mark.
Since it's MINUTE minutes past the hour, the hour hand will have
traveled fraction(MINUTE, 60) =
fraction(MINUTE, 60, false, true) of the way to the
1HOUR + 1
hour mark.
So the hour hand needs to be placed just before
the second small tick mark past the
HOUR
hour mark.
So the hour hand needs to be placed just past
the third small tick mark past the
HOUR
hour mark.
So the hour hand needs to be placed just past
the first small tick mark past the
HOUR
hour mark.
So the hour hand needs to be placed between the
second and third small tick mark past the
HOUR
hour mark.
So the hour hand needs to be placed just before
the fourth small tick mark past the
HOUR
hour mark.
var minuteRadius = minutePoint.constraints.fixedDistance.dist;
var hourRadius = hourPoint.constraints.fixedDistance.dist;
var minuteCoord = polar(minuteRadius, correctMinuteAngle);
var hourCoord = polar(hourRadius, correctHourAngle);
var dotOpacity = 0.4;
var handOpacity = 0.3;
addMovableLineSegment({
coordA: minuteCoord,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: ORANGE,
"stroke-width": 10,
"stroke-dasharray": ".",
"stroke-linecap": "round",
"stroke-opacity": dotOpacity
},
});
addMovableLineSegment({
coordA: minuteCoord,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: ORANGE,
"stroke-width": 10,
"stroke-linecap": "round",
"stroke-opacity": handOpacity
},
});
addMovableLineSegment({
coordA: hourCoord,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: BLUE,
"stroke-width": 10,
"stroke-dasharray": ".",
"stroke-linecap": "round",
"stroke-opacity": dotOpacity
},
});
addMovableLineSegment({
coordA: hourCoord,
coordZ: [0, 0],
fixed: true,
normalStyle: {
stroke: BLUE,
"stroke-width": 10,
"stroke-linecap": "round",
"stroke-opacity": handOpacity
},
});
// for some reason this doesn't work, so for now, create another center point
// centerPoint.toFront();
addMovablePoint({
coord: [0, 0],
constraints: {
fixed: true
},
normalStyle: {
fill: "#fff",
stroke: "#000",
"stroke-dasharray": "",
"stroke-width": 2,
"stroke-opacity": 1
}
});