Skip to content

Instantly share code, notes, and snippets.

@mritzco
Created March 10, 2017 09:28
Show Gist options
  • Save mritzco/25c25c73bb3cd6d4ddd99de0dfcca399 to your computer and use it in GitHub Desktop.
Save mritzco/25c25c73bb3cd6d4ddd99de0dfcca399 to your computer and use it in GitHub Desktop.
SVG Clock with duration
/* FROM LESS */
svg.clock {
background: #ffffff;
width: 120px;
height: 120px;
/* Don't define height - not overridable */
fill: none;
/* time markers */
/* Clock face and center */
}
svg.clock .duration {
stroke: #ccddee;
}
svg.clock .current {
stroke: #aaccee;
}
svg.clock path {
stroke: #ff0000;
}
svg.clock circle {
stroke: #446688;
}
svg#clocksmall {
width: 60px;
}
svg#clockmicro {
width: 30px;
}
svg#clockbig {
width: 100%;
}
/* jshint esversion: 6 */
/**
* Draws a clockface with duration and current hour indicator
*
* based on code from: http://stackoverflow.com/questions/5736398/how-to-calculate-the-svg-path-for-an-arc-of-a-circle by opsb
*/
const clock = {};
clock.polarToCartesian = function(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
};
clock.describeArc = function(x, y, radius, startAngle, endAngle){
var start = clock.polarToCartesian(x, y, radius, endAngle);
var end = clock.polarToCartesian(x, y, radius, startAngle);
var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");
return d;
};
/**
* Draws the clock markers, usually 4 or 12 but can be any number
* @method drawMarkers
* @param {svg} svg SVG element to draw
* @param {int} center Center coordinate (x==y)
* @param {int} r_markers Radius of markers (how far from center)
* @param {int} marker_size Length of marker_size
* @param {int} amount Number of markers (4/12 others)
* @return {null} nothing
*/
clock.drawMarkers = function(svg, center,r_markers,marker_size,amount) {
for (let m = 0; m < amount; m++) {
let pos = 360/amount * m;
let from = (pos===0 ? 359 : pos-1);
svg.appendChild(clock.addPath("path", {
"d": clock.describeArc(center, center, r_markers, from, pos+1),
"stroke-width": marker_size
}));
}
};
/**
* Function to create SVG objects and set properties
* @method addPath
* @param {string} shape a valid svg shape
* @param {object} props Collection of attributes to set
*/
clock.addPath = function(shape, props){
let newElement = document.createElementNS('http://www.w3.org/2000/svg',shape);
Object.keys(props).forEach(function(prop){
newElement.setAttribute(prop, props[prop]);
});
return newElement;
};
/**
* Entry point, draws a clock with duration and current hour markers
* It follow 12 hours clock, doesn't divide c/of into markers
* @method draw
* @param {svg} svg A reference or name of an svg object
* @param {int} c Current hour (1 hour segment)
* @param {int} of How many hours
* @param {int} [markers=4] How many hour markers to put on clock
* @return {null} nothing
*/
clock.draw = function(svg, c=0, of=0, markers=4) {
// Resize the container (and visualize)
if (typeof svg !== "object") svg = document.getElementById(svg);
if (!svg || svg.tagName !== "svg") throw ("Root not found or wrong type ", svg);
let box = svg.getBoundingClientRect();
const w = box.width,
padding = w * 0.01, /* Space to the edge of the svg */
stroke_face = w * 0.04, /* Stroke width base on image size */
r_face = (w - ((padding *2)+stroke_face )) / 2, /* radius of the face*/
r_center = w * 0.02, /* Radius of center circle*/
center = w/2, /* Center of the drawing (always square) */
r_inner = r_face - (stroke_face/2), /* radius to the inner border of the face*/
r_markers = r_face * 0.85, /* position of the markers (% from center to edge) */
marker_size = r_face * 0.10 /* How thick the markers appear */,
stroke_duration = r_face * 0.35 /* How thick the duration slice shows */,
r_duration = r_inner - (stroke_duration / 2) /* Radius of duration */;
/* Force height to be equal to width ~ must set height and style~*/
if (box.height !== w) {
svg.setAttribute("height", w);
svg.setAttribute("style", "height:"+w+"px" );
}
svg.appendChild(clock.addPath("path", {
"d": clock.describeArc( center, center, r_inner/2, (359/12 * 0), (359/12 * of)),
"stroke-width": r_inner,
"class": "duration"
}));
/* When current is 0 don't display at all */
if (c !== 0) {
svg.appendChild(clock.addPath("path", {
"d": clock.describeArc( center, center, r_duration , (359/12 * (c-1)), (359/12 * c)),
"stroke-width": stroke_duration,
"class": "current"
}));
}
// Draw the clock on top
svg.appendChild(clock.addPath("circle", {"cx": center, "cy": center, "r": r_face, "stroke-width": stroke_face }));
svg.appendChild(clock.addPath("circle", {"cx": center, "cy": center, "r": r_center, "stroke-width": stroke_face/2}));
clock.drawMarkers(svg, center,r_markers,marker_size, markers);
};
window.onload = function() {
clock.draw("clock", 1, 3, 4);
clock.draw("clocksmall", 1, 4, 12);
clock.draw("clockmicro", 1, 3, 12);
clock.draw("clockbig",3,3,12);
};
@size: 120px;
@color_background: #fff;
@color_duration: #CCDDEE;
@color_current: #AACCEE;
@color_markers: #f00;
@color_clock: #dff;
svg.clock{
background: @color_background;
width:@size;
height:@size;
/* Don't define height - not overridable */
fill: none;
.duration {
stroke: @color_duration;
}
.current {
stroke: @color_current;
}
/* time markers */
path {
stroke: @color_markers;
}
/* Clock face and center */
circle {
stroke: #446688;
}
}
svg#clocksmall {
width:60px;
}
svg#clockmicro {
width:30px;
}
svg#clockbig {
width:100%;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Clock sample</title>
</head>
<body>
<svg id="clock" class="clock"></svg>
<svg id="clocksmall" class="clock"></svg>
<svg id="clockmicro" class="clock"></svg>
<svg id="clockbig" class="clock"></svg>
</body>
</html>

Creates a clock face with 'n' markers (hours). It also marks a duration and the current time, i.e.

clock.draw("{svg_id}", current_hour, duration, hour_marks);

Tennis will take 3 hours, we're at 1st. Mark clock with 12 markers= clock.draw("svgid", 1,3,12);

Sample avalable at: http://jsbin.com/gupozaz/edit?html,css,js,console,output

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment