Download raw (6.9 KB)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Timeline</title> </head> <body> <object id="timeline" data="timeline.svg" type="image/svg+xml" style="max-height:90vh"></object> <script src="raphael.min.js"></script> <script> // lastDirection = 1; var loopSwitch = true, daySwitch = true, event = 0, day = 0, loop = 0, timelineSVG, highlightpath, timelineSegments; const timeline = [ [ [0], [0, 1, 2, 3], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], [0] ], [ [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5, 6, 7], [0] ], [ [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [0] ] ]; function timelineSubset(loop, day, event) { if (typeof(day) !== "undefined") { if(typeof(event) !== "undefined") { return timeline[loop][day][event]; } return timeline[loop][day]; } return timeline[loop]; } function getLength(input) { if (Array.isArray(input)) { // If the subpath has an uneven amount of children // on of them is positioned in the middle of the loop // therefor we loose a point on the loop var length = (input.length % 2 == 0) ? 3 : 2; for (var i=0;i<input.length;i++) { length += getLength(input[i]); } return length; } else { return 3; } } // If the parent(path) has an even amount of children, and the child // is located over the half of the path we have to insert and extra // point (top of the loop) function middlepointCompensation (parent, key) { if (key > 0 && (key + 1) * 2 > parent.length && parent.length % 2 == 0) { return 1; } else { return 0; } } function getStart(loop, day, event) { var coord = 1, l = 0, d = 0, e = 0; while (l < loop) { coord += getLength(timelineSubset(l)); l++; }; if (typeof(day) !== "undefined") { coord++; while (d < day) { coord += getLength(timelineSubset(l, d)); d++; } coord += middlepointCompensation(timelineSubset(l), d); if (typeof(event) !== "undefined") { coord++; while (e < event) { coord += getLength(timelineSubset(l,d,e)); e++; } coord += middlepointCompensation(timelineSubset(l,d), e); } } return coord; } function getEnd(loop, day, event) { var start = getStart(loop, day, event); if (typeof(event) !== 'undefined') { return start + getLength(timelineSubset(loop, day, event)); } else if (typeof(day) !== 'undefined') { return start + getLength(timelineSubset(loop, day)); } return start + getLength(timelineSubset(loop)); } function getSegmentCoords(segment) { if (segment[0] == 'C') { return [segment[5], segment[6]]; } else { return [segment[1], segment[2]]; } } function getSubpathFromSegments(segments, start, end) { subset = []; if (start > 0 || segments[start][0] !== 'M') { subset.push(['M'].concat(getSegmentCoords(segments[start-1]))); } return subset.concat(segments.slice(start, end+1)); } function makeCoordinateString(x, y) { return x + ' ' + y; } function makePathString(segments) { var pathstring = ''; for (var s = 0; s < segments.length;s++) { var command = segments[s][0]; coordinates = []; for (var c=1; c < segments[s].length; c+=2) { coordinates.push(makeCoordinateString(segments[s][c], segments[s][c+1])); } pathstring += command + coordinates.join(','); } return pathstring } function highlight(start, end) { highlightpath.setAttribute('d', makePathString(getSubpathFromSegments(timelineSegments, start, end))); } function highlightSection(loop, day, event) { highlight(getStart(loop, day, event)+1, getEnd(loop, day, event)-1); } function next () { // highlight next event // on loop switch higlight whole loop // on day switch highlight whole day // highlight previous event if (loopSwitch) { loopSwitch = false; // highlight loop highlightSection(loop, day) } else if (daySwitch) { daySwitch = false; highlightSection(loop, day, event); } else { event++; if (event >= timeline[loop][day].length) { // switch day, highlight day daySwitch = true; day++; if (day >= timeline[loop].length) { // switch loop highlight whole loop loopSwitch = true loop++; if (loop >= timeline.length) { loop = 0; } day = 0; highlightSection(loop); } else { highlightSection(loop, day); } event = 0; } else { highlightSection(loop, day, event); } } } function previous () { // highlight previous event if (loopSwitch) { loopSwitch = false; // highlight loop highlightSection(loop, day) } else if (daySwitch) { daySwitch = false; // on day switch higlight whole day // switch day, highlight day highlightSection(loop, day, event); } else { event--; if (event < 0) { daySwitch = true; day--; if (day < 0) { // switch loop highlight whole loop loopSwitch = true loop--; if (loop < 0) { loop = timeline.length-1; } highlightSection(loop); day = timeline[loop].length - 1; } else { highlightSection(loop, day); } event = timeline[loop][day].length - 1; } else { highlightSection(loop, day, event); } } } window.addEventListener('load', function () { timelineSVG = document.querySelector('#timeline').contentDocument.rootElement; const paths = timelineSVG.querySelectorAll('path'); highlightpath = paths[5]; //document.querySelector('#timeline').contentDocument.createElement('path'); timelineSegments = Raphael.parsePathString(paths[4].getAttribute('d')); highlightpath.setAttribute("style", "stroke:rgb(100%,0%,0%); stroke-width:5.0;fill:none;"); window.addEventListener('wheel', function (e) { (e.deltaY > 0) ? next() : previous(); }); highlightSection(loop); }); </script> </body> </html>