randRange(1, 12) 15 randRange(0, (60 / MINUTE_INCREMENT) - 1) * MINUTE_INCREMENT
MINUTE === 0 MINUTE > 5 ? MINUTE : "0" + MINUTE HOUR + ":" + NICE_MINUTE

Set the clock to TIME.

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 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 just past the third just past the first between the second and third 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 } });
20
30