1(function() { 2 // Horizontal Timeline - by CodyHouse.co 3 var HorizontalTimeline = function(element) { 4 this.element = element; 5 this.datesContainer = this.element.getElementsByClassName('cd-h-timeline__dates')[0]; 6 this.line = this.datesContainer.getElementsByClassName('cd-h-timeline__line')[0]; // grey line in the top timeline section 7 this.fillingLine = this.datesContainer.getElementsByClassName('cd-h-timeline__filling-line')[0]; // green filling line in the top timeline section 8 this.date = this.line.getElementsByClassName('cd-h-timeline__date'); 9 this.selectedDate = this.line.getElementsByClassName('cd-h-timeline__date--selected')[0]; 10 this.dateValues = parseDate(this); 11 this.minLapse = calcMinLapse(this); 12 this.navigation = this.element.getElementsByClassName('cd-h-timeline__navigation'); 13 this.contentWrapper = this.element.getElementsByClassName('cd-h-timeline__events')[0]; 14 this.content = this.contentWrapper.getElementsByClassName('cd-h-timeline__event'); 15 16 this.eventsMinDistance = 60; // min distance between two consecutive events (in px) 17 this.eventsMaxDistance = 200; // max distance between two consecutive events (in px) 18 this.translate = 0; // this will be used to store the translate value of this.line 19 this.lineLength = 0; //total length of this.line 20 21 // store index of selected and previous selected dates 22 this.oldDateIndex = Util.getIndexInArray(this.date, this.selectedDate); 23 this.newDateIndex = this.oldDateIndex; 24 25 initTimeline(this); 26 initEvents(this); 27 }; 28 29 function initTimeline(timeline) { 30 // set dates left position 31 var left = 0; 32 for (var i = 0; i < timeline.dateValues.length; i++) { 33 var j = (i == 0) ? 0 : i - 1; 34 var distance = daydiff(timeline.dateValues[j], timeline.dateValues[i]), 35 distanceNorm = (Math.round(distance/timeline.minLapse) + 2)*timeline.eventsMinDistance; 36 37 if(distanceNorm < timeline.eventsMinDistance) { 38 distanceNorm = timeline.eventsMinDistance; 39 } else if(distanceNorm > timeline.eventsMaxDistance) { 40 distanceNorm = timeline.eventsMaxDistance; 41 } 42 left = left + distanceNorm; 43 timeline.date[i].setAttribute('style', 'left:' + left+'px'); 44 } 45 46 // set line/filling line dimensions 47 timeline.line.style.width = (left + timeline.eventsMinDistance)+'px'; 48 timeline.lineLength = left + timeline.eventsMinDistance; 49 // reveal timeline 50 Util.addClass(timeline.element, 'cd-h-timeline--loaded'); 51 selectNewDate(timeline, timeline.selectedDate); 52 resetTimelinePosition(timeline, 'next'); 53 }; 54 55 function initEvents(timeline) { 56 var self = timeline; 57 // click on arrow navigation 58 self.navigation[0].addEventListener('click', function(event){ 59 event.preventDefault(); 60 translateTimeline(self, 'prev'); 61 }); 62 self.navigation[1].addEventListener('click', function(event){ 63 event.preventDefault(); 64 translateTimeline(self, 'next'); 65 }); 66 67 //swipe on timeline 68 new SwipeContent(self.datesContainer); 69 self.datesContainer.addEventListener('swipeLeft', function(event){ 70 translateTimeline(self, 'next'); 71 }); 72 self.datesContainer.addEventListener('swipeRight', function(event){ 73 translateTimeline(self, 'prev'); 74 }); 75 76 //select a new event 77 for(var i = 0; i < self.date.length; i++) { 78 (function(i){ 79 self.date[i].addEventListener('click', function(event){ 80 event.preventDefault(); 81 selectNewDate(self, event.target); 82 }); 83 84 self.content[i].addEventListener('animationend', function(event){ 85 if( i == self.newDateIndex && self.newDateIndex != self.oldDateIndex) resetAnimation(self); 86 }); 87 })(i); 88 } 89 }; 90 91 function updateFilling(timeline) { // update fillingLine scale value 92 var dateStyle = window.getComputedStyle(timeline.selectedDate, null), 93 left = dateStyle.getPropertyValue("left"), 94 width = dateStyle.getPropertyValue("width"); 95 96 left = Number(left.replace('px', '')) + Number(width.replace('px', ''))/2; 97 timeline.fillingLine.style.transform = 'scaleX('+(left/timeline.lineLength)+')'; 98 }; 99 100 function translateTimeline(timeline, direction) { // translate timeline (and date elements) 101 var containerWidth = timeline.datesContainer.offsetWidth; 102 if(direction) { 103 timeline.translate = (direction == 'next') ? timeline.translate - containerWidth + timeline.eventsMinDistance : timeline.translate + containerWidth - timeline.eventsMinDistance; 104 } 105 if( 0 - timeline.translate > timeline.lineLength - containerWidth ) timeline.translate = containerWidth - timeline.lineLength; 106 if( timeline.translate > 0 ) timeline.translate = 0; 107 108 timeline.line.style.transform = 'translateX('+timeline.translate+'px)'; 109 // update the navigation items status (toggle inactive class) 110 (timeline.translate == 0 ) ? Util.addClass(timeline.navigation[0], 'cd-h-timeline__navigation--inactive') :
110Util.removeClass(timeline.navigation[0], 'cd-h-timeline__navigation--inactive'); 111 (timeline.translate == containerWidth - timeline.lineLength ) ? Util.addClass(timeline.navigation[1], 'cd-h-timeline__navigation--inactive') : Util.removeClass(timeline.navigation[1], 'cd-h-timeline__navigation--inactive'); 112 }; 113 114 function selectNewDate(timeline, target) { // ned date has been selected -> update timeline 115 timeline.newDateIndex = Util.getIndexInArray(timeline.date, target); 116 timeline.oldDateIndex = Util.getIndexInArray(timeline.date, timeline.selectedDate); 117 Util.removeClass(timeline.selectedDate, 'cd-h-timeline__date--selected'); 118 Util.addClass(timeline.date[timeline.newDateIndex], 'cd-h-timeline__date--selected'); 119 timeline.selectedDate = timeline.date[timeline.newDateIndex]; 120 updateOlderEvents(timeline); 121 updateVisibleContent(timeline); 122 updateFilling(timeline); 123 }; 124 125 function updateOlderEvents(timeline) { // update older events style 126 for(var i = 0; i < timeline.date.length; i++) { 127 (i < timeline.newDateIndex) ? Util.addClass(timeline.date[i], 'cd-h-timeline__date--older-event') : Util.removeClass(timeline.date[i], 'cd-h-timeline__date--older-event'); 128 } 129 }; 130 131 function updateVisibleContent(timeline) { // show content of new selected date 132 if (timeline.newDateIndex > timeline.oldDateIndex) { 133 var classEntering = 'cd-h-timeline__event--selected cd-h-timeline__event--enter-right', 134 classLeaving = 'cd-h-timeline__event--leave-left'; 135 } else if(timeline.newDateIndex < timeline.oldDateIndex) { 136 var classEntering = 'cd-h-timeline__event--selected cd-h-timeline__event--enter-left', 137 classLeaving = 'cd-h-timeline__event--leave-right'; 138 } else { 139 var classEntering = 'cd-h-timeline__event--selected', 140 classLeaving = ''; 141 } 142 143 Util.addClass(timeline.content[timeline.newDateIndex], classEntering); 144 if (timeline.newDateIndex != timeline.oldDateIndex) { 145 Util.removeClass(timeline.content[timeline.oldDateIndex], 'cd-h-timeline__event--selected'); 146 Util.addClass(timeline.content[timeline.oldDateIndex], classLeaving); 147 timeline.contentWrapper.style.height = timeline.content[timeline.newDateIndex].offsetHeight + 'px'; 148 } 149 }; 150 151 function resetAnimation(timeline) { // reset content classes when entering animation is over 152 timeline.contentWrapper.style.height = null; 153 Util.removeClass(timeline.content[timeline.newDateIndex], 'cd-h-timeline__event--enter-right cd-h-timeline__event--enter-left'); 154 Util.removeClass(timeline.content[timeline.oldDateIndex], 'cd-h-timeline__event--leave-right cd-h-timeline__event--leave-left'); 155 }; 156 157 function keyNavigateTimeline(timeline, direction) { // navigate the timeline using the keyboard 158 var newIndex = (direction == 'next') ? timeline.newDateIndex + 1 : timeline.newDateIndex - 1; 159 if(newIndex < 0 || newIndex >= timeline.date.length) return; 160 selectNewDate(timeline, timeline.date[newIndex]); 161 resetTimelinePosition(timeline, direction); 162 }; 163 164 function resetTimelinePosition(timeline, direction) { //translate timeline according to new selected event position 165 var eventStyle = window.getComputedStyle(timeline.selectedDate, null), 166 eventLeft = Number(eventStyle.getPropertyValue('left').replace('px', '')), 167 timelineWidth = timeline.datesContainer.offsetWidth; 168 169 if( (direction == 'next' && eventLeft >= timelineWidth - timeline.translate) || (direction == 'prev' && eventLeft <= - timeline.translate) ) { 170 timeline.translate = timelineWidth/2 - eventLeft; 171 translateTimeline(timeline, false); 172 } 173 }; 174 175 function parseDate(timeline) { // get timestamp value for each date 176 var dateArrays = []; 177 for(var i = 0; i < timeline.date.length; i++) { 178 var singleDate = timeline.date[i].getAttribute('data-date'), 179 dateComp = singleDate.split('T'); 180 181 if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided 182 var dayComp = dateComp[0].split('/'), 183 timeComp = dateComp[1].split(':'); 184 } else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide 185 var dayComp = ["2000", "0", "0"], 186 timeComp = dateComp[0].split(':'); 187 } else { //only DD/MM/YEAR 188 var dayComp = dateComp[0].split('/'), 189 timeComp = ["0", "0"]; 190 } 191 var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]); 192 dateArrays.push(newDate); 193 } 194 return dateArrays; 195 }; 196 197 function calcMinLapse(timeline) { // determine the minimum distance among events 198 var dateDistances = []; 199 for(var i = 1; i < timeline.dateValues.length; i++) { 200 var distance = daydiff(timeline.dateValues[i-1], timeline.dateValues[i]); 201 if(distance > 0) dateDistances.push(distance); 202 } 203 204 return (dateDistances.length > 0 ) ? Math.min.apply(null, dateDistances) : 86400000; 205 }; 206 207 function daydiff(first, second) { // time distance between events 208 return Math.round((second-first)); 209 }; 210 211 window.HorizontalTimeline = HorizontalTimeline; 212 213 var horizontalTimeline = document.getElementsByClassName('js-cd-h-timeline'), 214 horizontalTimelineTimelineArray = []; 215 if(horizontalTimeline.length > 0) { 216 for(var i = 0; i < horizontalTimeline.length; i++) { 217 horizontalTimelineTimelineArray.push(new HorizontalTimeline(horizontalTimeline[i])); 218 } 219 // navigate the timeline when inside the viewport using the keyboard 220 document.addEventListener('keydown', function(event){ 221 if( (event.keyCode && event.keyCode == 39) || ( event.key && event.key.toLowerCase() == 'arrowright') ) { 222 updateHorizontalTimeline('next'); // move to next event 223 } else if((event.keyCode && event.keyCode == 37) || ( event.key && event.key.toLowerCase() == 'arrowleft')) { 224 updateHorizontalTimeline('prev'); // move to prev event 225 } 226 }); 227 }; 228 229 function updateHorizontalTimeline(direction) { 230 for(var i = 0; i < horizontalTimelineTimelineArray.length; i++) { 231 if(elementInViewport(horizontalTimeline[i])) keyNavigateTimeline(horizontalTimelineTimelineArray[i], direction); 232 } 233 }; 234 235 /* 236 How to tell if a DOM element is visible in the current viewport? 237 http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport 238 */ 239 function elementInViewport(el) { 240 var top = el.offsetTop; 241 var left = el.offsetLeft; 242 var width = el.offsetWidth; 243 var height = el.offsetHeight; 244 245 while(el.offsetParent) { 246 el = el.offsetParent; 247 top += el.offsetTop; 248 left += el.offsetLeft; 249 } 250 251 return ( 252 top < (window.pageYOffset + window.innerHeight) && 253 left < (window.pageXOffset + window.innerWidth) && 254 (top + height) > window.pageYOffset && 255 (left + width) > window.pageXOffset 256 ); 257 } 258}());
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.