/* TimeNav This class handles the bottom timeline navigation. It requires the VMM.Util class and VMM.Date class ================================================== */ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefined') { VMM.Timeline.TimeNav = function(parent, content_width, content_height) { trace("VMM.Timeline.TimeNav"); var $timenav, $content, $time, $timeintervalminor, $timeinterval, $timeintervalmajor, $timebackground, $timeintervalbackground, $timenavline, $timenavindicator, $timeintervalminor_minor, $toolbar, $zoomin, $zoomout, $dragslide, config = VMM.Timeline.Config, row_height, events = {}, timespan = {}, layout = parent, data = [], era_markers = [], markers = [], interval_array = [], interval_major_array = [], tags = [], current_marker = 0, _active = false, eras, content, timeouts = { interval_position: "" }, timenav_pos = { left: "", visible: { left: "", right: "" } }, timelookup = { day: 24, month: 12, year: 10, hour: 60, minute: 60, second: 1000, decade: 10, century: 100, millenium: 1000, age: 1000000, epoch: 10000000, era: 100000000, eon: 500000000, week: 4.34812141, days_in_month: 30.4368499, days_in_week: 7, weeks_in_month: 4.34812141, weeks_in_year: 52.177457, days_in_year: 365.242199, hours_in_day: 24 }, dateFractionBrowser = { day: 86400000, week: 7, month: 30.4166666667, year: 12, hour: 24, minute: 1440, second: 86400, decade: 10, century: 100, millenium: 1000, age: 1000000, epoch: 10000000, era: 100000000, eon: 500000000 }, interval = { type: "year", number: 10, first: 1970, last: 2011, multiplier: 100, classname: "_idd", interval_type: "interval" }, interval_major = { type: "year", number: 10, first: 1970, last: 2011, multiplier: 100, classname: "major", interval_type: "interval major" }, interval_macro = { type: "year", number: 10, first: 1970, last: 2011, multiplier: 100, classname: "_dd_minor", interval_type: "interval minor" }, interval_calc = { day: {}, month: {}, year: {}, hour: {}, minute: {}, second: {}, decade: {}, century: {}, millenium: {}, week: {}, age: {}, epoch: {}, era: {}, eon: {} }; /* ADD to Config ================================================== */ row_height = config.nav.marker.height/2; config.nav.rows = { full: [1, row_height*2, row_height*4], half: [1, row_height, row_height*2, row_height*3, row_height*4, row_height*5], current: [] } if (content_width != null && content_width != "") { config.nav.width = content_width; } if (content_height != null && content_height != "") { config.nav.height = content_height; } /* INIT ================================================== */ this.init = function(d,e) { trace('VMM.Timeline.TimeNav init'); // need to evaluate d // some function to determine type of data and prepare it if(typeof d != 'undefined') { this.setData(d, e); } else { trace("WAITING ON DATA"); } }; /* GETTERS AND SETTERS ================================================== */ this.setData = function(d,e) { if(typeof d != 'undefined') { data = {}; data = d; eras = e; build(); } else{ trace("NO DATA"); } }; this.setSize = function(w, h) { if (w != null) {config.width = w}; if (h != null) {config.height = h}; if (_active) { reSize(); } } this.setMarker = function(n, ease, duration, fast) { goToMarker(n, ease, duration); } this.getCurrentNumber = function() { return current_marker; } /* ON EVENT ================================================== */ function onConfigSet() { trace("onConfigSet"); }; function reSize(firstrun) { config.nav.constraint.left = (config.width/2); config.nav.constraint.right = config.nav.constraint.right_min - (config.width/2); $dragslide.updateConstraint(config.nav.constraint); VMM.Lib.css($timenavline, "left", Math.round(config.width/2)+2); VMM.Lib.css($timenavindicator, "left", Math.round(config.width/2)-8); goToMarker(config.current_slide, config.ease, config.duration, true, firstrun); }; function upDate() { VMM.fireEvent(layout, "UPDATE"); } function onZoomIn() { $dragslide.cancelSlide(); if (config.nav.multiplier.current > config.nav.multiplier.min) { if (config.nav.multiplier.current <= 1) { config.nav.multiplier.current = config.nav.multiplier.current - .25; } else { if (config.nav.multiplier.current > 5) { if (config.nav.multiplier.current > 16) { config.nav.multiplier.current = Math.round(config.nav.multiplier.current - 10); } else { config.nav.multiplier.current = Math.round(config.nav.multiplier.current - 4); } } else { config.nav.multiplier.current = Math.round(config.nav.multiplier.current - 1); } } if (config.nav.multiplier.current <= 0) { config.nav.multiplier.current = config.nav.multiplier.min; } refreshTimeline(); } } function onZoomOut() { $dragslide.cancelSlide(); if (config.nav.multiplier.current < config.nav.multiplier.max) { if (config.nav.multiplier.current > 4) { if (config.nav.multiplier.current > 16) { config.nav.multiplier.current = Math.round(config.nav.multiplier.current + 10); } else { config.nav.multiplier.current = Math.round(config.nav.multiplier.current + 4); } } else { config.nav.multiplier.current = Math.round(config.nav.multiplier.current + 1); } if (config.nav.multiplier.current >= config.nav.multiplier.max) { config.nav.multiplier.current = config.nav.multiplier.max; } refreshTimeline(); } } function onBackHome(e) { $dragslide.cancelSlide(); goToMarker(0); upDate(); } function onMouseScroll(e) { var delta = 0, scroll_to = 0; if (!e) { e = window.event; } if (e.originalEvent) { e = e.originalEvent; } // Browsers unable to differntiate between up/down and left/right scrolling /* if (e.wheelDelta) { delta = e.wheelDelta/6; } else if (e.detail) { delta = -e.detail*12; } */ // Webkit and browsers able to differntiate between up/down and left/right scrolling if (typeof e.wheelDeltaX != 'undefined' ) { delta = e.wheelDeltaY/6; if (Math.abs(e.wheelDeltaX) > Math.abs(e.wheelDeltaY)) { delta = e.wheelDeltaX/6; } else { //delta = e.wheelDeltaY/6; delta = 0; } } if (delta) { if (e.preventDefault) { e.preventDefault(); } e.returnValue = false; } // Stop from scrolling too far scroll_to = VMM.Lib.position($timenav).left + delta; if (scroll_to > config.nav.constraint.left) { scroll_to = config.width/2; } else if (scroll_to < config.nav.constraint.right) { scroll_to = config.nav.constraint.right; } //VMM.Lib.stop($timenav); //VMM.Lib.animate($timenav, config.duration/2, "linear", {"left": scroll_to}); VMM.Lib.css($timenav, "left", scroll_to); } function refreshTimeline() { trace("config.nav.multiplier " + config.nav.multiplier.current); positionMarkers(true); positionEras(true); positionInterval($timeinterval, interval_array, true, true); positionInterval($timeintervalmajor, interval_major_array, true); config.nav.constraint.left = (config.width/2); config.nav.constraint.right = config.nav.constraint.right_min - (config.width/2); $dragslide.updateConstraint(config.nav.constraint); }; /* MARKER EVENTS ================================================== */ function onMarkerClick(e) { $dragslide.cancelSlide(); goToMarker(e.data.number); upDate(); }; function onMarkerHover(e) { VMM.Lib.toggleClass(e.data.elem, "zFront"); }; function goToMarker(n, ease, duration, fast, firstrun) { trace("GO TO MARKER"); var _ease = config.ease, _duration = config.duration, is_last = false, is_first = false; current_marker = n; timenav_pos.left = (config.width/2) - markers[current_marker].pos_left timenav_pos.visible.left = Math.abs(timenav_pos.left) - 100; timenav_pos.visible.right = Math.abs(timenav_pos.left) + config.width + 100; if (current_marker == 0) { is_first = true; } if (current_marker +1 == markers.length) { is_last = true } if (ease != null && ease != "") {_ease = ease}; if (duration != null && duration != "") {_duration = duration}; // set marker style for(var i = 0; i < markers.length; i++) { VMM.Lib.removeClass(markers[i].marker, "active"); } if (config.start_page && markers[0].type == "start") { VMM.Lib.visible(markers[0].marker, false); VMM.Lib.addClass(markers[0].marker, "start"); } VMM.Lib.addClass(markers[current_marker].marker, "active"); // ANIMATE MARKER VMM.Lib.stop($timenav); VMM.Lib.animate($timenav, _duration, _ease, {"left": timenav_pos.left}); } /* TOUCH EVENTS ================================================== */ function onTouchUpdate(e, b) { VMM.Lib.animate($timenav, b.time/2, config.ease, {"left": b.left}); }; /* CALCULATIONS ================================================== */ function averageMarkerPositionDistance() { var last_pos = 0, pos = 0, pos_dif = 0, mp_diff = [], i = 0; for(i = 0; i < markers.length; i++) { if (data[i].type == "start") { } else { var _pos = positionOnTimeline(interval, markers[i].relative_pos), last_pos = pos; pos = _pos.begin; pos_dif = pos - last_pos; mp_diff.push(pos_dif); } } return VMM.Util.average(mp_diff).mean; } function averageDateDistance() { var last_dd = 0, dd = 0, _dd = "", date_dif = 0, date_diffs = [], is_first_date = true, i = 0; for(i = 0; i < data.length; i++) { if (data[i].type == "start") { trace("DATA DATE IS START") } else { _dd = data[i].startdate; last_dd = dd; dd = _dd; date_dif = dd - last_dd; date_diffs.push(date_dif); } } return VMM.Util.average(date_diffs); } function calculateMultiplier() { var temp_multiplier = config.nav.multiplier.current, i = 0; for(i = 0; i < temp_multiplier; i++) { if (averageMarkerPositionDistance() < 75) { if (config.nav.multiplier.current > 1) { config.nav.multiplier.current = (config.nav.multiplier.current - 1); } } } } function calculateInterval() { // NEED TO REWRITE ALL OF THIS var _first = getDateFractions(data[0].startdate), _last = getDateFractions(data[data.length - 1].enddate); // EON interval_calc.eon.type = "eon"; interval_calc.eon.first = _first.eons; interval_calc.eon.base = Math.floor(_first.eons); interval_calc.eon.last = _last.eons; interval_calc.eon.number = timespan.eons; interval_calc.eon.multiplier = timelookup.eons; interval_calc.eon.minor = timelookup.eons; // ERA interval_calc.era.type = "era"; interval_calc.era.first = _first.eras; interval_calc.era.base = Math.floor(_first.eras); interval_calc.era.last = _last.eras; interval_calc.era.number = timespan.eras; interval_calc.era.multiplier = timelookup.eras; interval_calc.era.minor = timelookup.eras; // EPOCH interval_calc.epoch.type = "epoch"; interval_calc.epoch.first = _first.epochs; interval_calc.epoch.base = Math.floor(_first.epochs); interval_calc.epoch.last = _last.epochs; interval_calc.epoch.number = timespan.epochs; interval_calc.epoch.multiplier = timelookup.epochs; interval_calc.epoch.minor = timelookup.epochs; // AGE interval_calc.age.type = "age"; interval_calc.age.first = _first.ages; interval_calc.age.base = Math.floor(_first.ages); interval_calc.age.last = _last.ages; interval_calc.age.number = timespan.ages; interval_calc.age.multiplier = timelookup.ages; interval_calc.age.minor = timelookup.ages; // MILLENIUM interval_calc.millenium.type = "millenium"; interval_calc.millenium.first = _first.milleniums; interval_calc.millenium.base = Math.floor(_first.milleniums); interval_calc.millenium.last = _last.milleniums; interval_calc.millenium.number = timespan.milleniums; interval_calc.millenium.multiplier = timelookup.millenium; interval_calc.millenium.minor = timelookup.millenium; // CENTURY interval_calc.century.type = "century"; interval_calc.century.first = _first.centuries; interval_calc.century.base = Math.floor(_first.centuries); interval_calc.century.last = _last.centuries; interval_calc.century.number = timespan.centuries; interval_calc.century.multiplier = timelookup.century; interval_calc.century.minor = timelookup.century; // DECADE interval_calc.decade.type = "decade"; interval_calc.decade.first = _first.decades; interval_calc.decade.base = Math.floor(_first.decades); interval_calc.decade.last = _last.decades; interval_calc.decade.number = timespan.decades; interval_calc.decade.multiplier = timelookup.decade; interval_calc.decade.minor = timelookup.decade; // YEAR interval_calc.year.type = "year"; interval_calc.year.first = _first.years; interval_calc.year.base = Math.floor(_first.years); interval_calc.year.last = _last.years; interval_calc.year.number = timespan.years; interval_calc.year.multiplier = 1; interval_calc.year.minor = timelookup.month; // MONTH interval_calc.month.type = "month"; interval_calc.month.first = _first.months; interval_calc.month.base = Math.floor(_first.months); interval_calc.month.last = _last.months; interval_calc.month.number = timespan.months; interval_calc.month.multiplier = 1; interval_calc.month.minor = Math.round(timelookup.week); // WEEK // NOT DONE interval_calc.week.type = "week"; interval_calc.week.first = _first.weeks; interval_calc.week.base = Math.floor(_first.weeks); interval_calc.week.last = _last.weeks; interval_calc.week.number = timespan.weeks; interval_calc.week.multiplier = 1; interval_calc.week.minor = 7; // DAY interval_calc.day.type = "day"; interval_calc.day.first = _first.days; interval_calc.day.base = Math.floor(_first.days); interval_calc.day.last = _last.days; interval_calc.day.number = timespan.days; interval_calc.day.multiplier = 1; interval_calc.day.minor = 24; // HOUR interval_calc.hour.type = "hour"; interval_calc.hour.first = _first.hours; interval_calc.hour.base = Math.floor(_first.hours); interval_calc.hour.last = _last.hours; interval_calc.hour.number = timespan.hours; interval_calc.hour.multiplier = 1; interval_calc.hour.minor = 60; // MINUTE interval_calc.minute.type = "minute"; interval_calc.minute.first = _first.minutes; interval_calc.minute.base = Math.floor(_first.minutes); interval_calc.minute.last = _last.minutes; interval_calc.minute.number = timespan.minutes; interval_calc.minute.multiplier = 1; interval_calc.minute.minor = 60; // SECOND interval_calc.second.type = "decade"; interval_calc.second.first = _first.seconds; interval_calc.second.base = Math.floor(_first.seconds); interval_calc.second.last = _last.seconds; interval_calc.second.number = timespan.seconds; interval_calc.second.multiplier = 1; interval_calc.second.minor = 10; } function getDateFractions(the_date, is_utc) { var _time = {}; _time.days = the_date / dateFractionBrowser.day; _time.weeks = _time.days / dateFractionBrowser.week; _time.months = _time.days / dateFractionBrowser.month; _time.years = _time.months / dateFractionBrowser.year; _time.hours = _time.days * dateFractionBrowser.hour; _time.minutes = _time.days * dateFractionBrowser.minute; _time.seconds = _time.days * dateFractionBrowser.second; _time.decades = _time.years / dateFractionBrowser.decade; _time.centuries = _time.years / dateFractionBrowser.century; _time.milleniums = _time.years / dateFractionBrowser.millenium; _time.ages = _time.years / dateFractionBrowser.age; _time.epochs = _time.years / dateFractionBrowser.epoch; _time.eras = _time.years / dateFractionBrowser.era; _time.eons = _time.years / dateFractionBrowser.eon; /* trace("AGES " + _time.ages); trace("EPOCHS " + _time.epochs); trace("MILLENIUMS " + _time.milleniums); trace("CENTURIES " + _time.centuries); trace("DECADES " + _time.decades); trace("YEARS " + _time.years); trace("MONTHS " + _time.months); trace("WEEKS " + _time.weeks); trace("DAYS " + _time.days); trace("HOURS " + _time.hours); trace("MINUTES " + _time.minutes); trace("SECONDS " + _time.seconds); */ return _time; } /* POSITION Positions elements on the timeline based on date relative to the calculated interval ================================================== */ function positionRelative(_interval, first, last) { var _first, _last, _type = _interval.type, timerelative = { start: "", end: "", type: _type }; /* FIRST ================================================== */ _first = getDateFractions(first); timerelative.start = first.months; if (_type == "eon") { timerelative.start = _first.eons; } else if (_type == "era") { timerelative.start = _first.eras; } else if (_type == "epoch") { timerelative.start = _first.epochs; } else if (_type == "age") { timerelative.start = _first.ages; } else if (_type == "millenium") { timerelative.start = first.milleniums; } else if (_type == "century") { timerelative.start = _first.centuries; } else if (_type == "decade") { timerelative.start = _first.decades; } else if (_type == "year") { timerelative.start = _first.years; } else if (_type == "month") { timerelative.start = _first.months; } else if (_type == "week") { timerelative.start = _first.weeks; } else if (_type == "day") { timerelative.start = _first.days; } else if (_type == "hour") { timerelative.start = _first.hours; } else if (_type == "minute") { timerelative.start = _first.minutes; } /* LAST ================================================== */ if (type.of(last) == "date") { _last = getDateFractions(last); timerelative.end = last.months; if (_type == "eon") { timerelative.end = _last.eons; } else if (_type == "era") { timerelative.end = _last.eras; } else if (_type == "epoch") { timerelative.end = _last.epochs; } else if (_type == "age") { timerelative.end = _last.ages; } else if (_type == "millenium") { timerelative.end = last.milleniums; } else if (_type == "century") { timerelative.end = _last.centuries; } else if (_type == "decade") { timerelative.end = _last.decades; } else if (_type == "year") { timerelative.end = _last.years; } else if (_type == "month") { timerelative.end = _last.months; } else if (_type == "week") { timerelative.end = _last.weeks; } else if (_type == "day") { timerelative.end = _last.days; } else if (_type == "hour") { timerelative.end = _last.hours; } else if (_type == "minute") { timerelative.end = _last.minutes; } } else { timerelative.end = timerelative.start; } return timerelative } function positionOnTimeline(the_interval, timerelative) { return { begin: (timerelative.start - interval.base) * (config.nav.interval_width / config.nav.multiplier.current), end: (timerelative.end - interval.base) * (config.nav.interval_width / config.nav.multiplier.current) }; } function positionMarkers(is_animated) { var row = 2, previous_pos = 0, pos_offset = -2, row_depth = 0, row_depth_sub = 0, line_last_height_pos = 150, line_height = 6, cur_mark = 0, in_view_margin = config.width, pos_cache_array = [], pos_cache_max = 6, in_view = { left: timenav_pos.visible.left - in_view_margin, right: timenav_pos.visible.right + in_view_margin }, i = 0, k = 0; config.nav.minor_width = config.width; VMM.Lib.removeClass(".flag", "row1"); VMM.Lib.removeClass(".flag", "row2"); VMM.Lib.removeClass(".flag", "row3"); for(i = 0; i < markers.length; i++) { var line, marker = markers[i], pos = positionOnTimeline(interval, markers[i].relative_pos), row_pos = 0, is_in_view = false, pos_cache_obj = {id: i, pos: 0, row: 0}, pos_cache_close = 0; // COMPENSATE FOR DATES BEING POITIONED IN THE MIDDLE pos.begin = Math.round(pos.begin + pos_offset); pos.end = Math.round(pos.end + pos_offset); line = Math.round(pos.end - pos.begin); marker.pos_left = pos.begin; if (current_marker == i) { timenav_pos.left = (config.width/2) - pos; timenav_pos.visible.left = Math.abs(timenav_pos.left); timenav_pos.visible.right = Math.abs(timenav_pos.left) + config.width; in_view.left = timenav_pos.visible.left - in_view_margin; in_view.right = timenav_pos.visible.right + in_view_margin; } if (Math.abs(pos.begin) >= in_view.left && Math.abs(pos.begin) <= in_view.right ) { is_in_view = true; } // APPLY POSITION TO MARKER if (is_animated) { VMM.Lib.stop(marker.marker); VMM.Lib.animate(marker.marker, config.duration/2, config.ease, {"left": pos.begin}); } else { VMM.Lib.stop(marker.marker); VMM.Lib.css(marker.marker, "left", pos.begin); } if (i == current_marker) { cur_mark = pos.begin; } // EVENT LENGTH LINE if (line > 5) { VMM.Lib.css(marker.lineevent, "height", line_height); VMM.Lib.css(marker.lineevent, "top", line_last_height_pos); if (is_animated) { VMM.Lib.animate(marker.lineevent, config.duration/2, config.ease, {"width": line}); } else { VMM.Lib.css(marker.lineevent, "width", line); } } // CONTROL ROW POSITION if (tags.length > 0) { for (k = 0; k < tags.length; k++) { if (k < config.nav.rows.current.length) { if (marker.tag == tags[k]) { row = k; if (k == config.nav.rows.current.length - 1) { trace("ON LAST ROW"); VMM.Lib.addClass(marker.flag, "flag-small-last"); } } } } row_pos = config.nav.rows.current[row]; } else { if (pos.begin - previous_pos.begin < (config.nav.marker.width + config.spacing)) { if (row < config.nav.rows.current.length - 1) { row ++; } else { row = 0; row_depth ++; } } else { row_depth = 1; row = 1; } row_pos = config.nav.rows.current[row]; } // SET LAST MARKER POSITION previous_pos = pos; // POSITION CACHE pos_cache_obj.pos = pos; pos_cache_obj.row = row; pos_cache_array.push(pos_cache_obj); if (pos_cache_array.length > pos_cache_max) { pos_cache_array.remove(0); } //if (is_animated && is_in_view) { if (is_animated) { VMM.Lib.stop(marker.flag); VMM.Lib.animate(marker.flag, config.duration, config.ease, {"top": row_pos}); } else { VMM.Lib.stop(marker.flag); VMM.Lib.css(marker.flag, "top", row_pos); } // IS THE MARKER A REPRESENTATION OF A START SCREEN? if (config.start_page && markers[i].type == "start") { VMM.Lib.visible(marker.marker, false); } if (pos > config.nav.minor_width) { config.nav.minor_width = pos; } if (pos < config.nav.minor_left) { config.nav.minor_left = pos; } } // ANIMATE THE TIMELINE TO ADJUST TO CHANGES if (is_animated) { VMM.Lib.stop($timenav); VMM.Lib.animate($timenav, config.duration/2, config.ease, {"left": (config.width/2) - (cur_mark)}); } else { } //VMM.Lib.delay_animate(config.duration, $timenav, config.duration/2, config.ease, {"left": (config.width/2) - (cur_mark)}); } function positionEras(is_animated) { var i = 0, p = 0; for(i = 0; i < era_markers.length; i++) { var era = era_markers[i], pos = positionOnTimeline(interval, era.relative_pos), row_pos = 0, row = 0, era_height = config.nav.marker.height * config.nav.rows.full.length, era_length = pos.end - pos.begin; // CONTROL ROW POSITION if (era.tag != "") { era_height = (config.nav.marker.height * config.nav.rows.full.length) / config.nav.rows.current.length; for (p = 0; p < tags.length; p++) { if (p < config.nav.rows.current.length) { if (era.tag == tags[p]) { row = p; } } } row_pos = config.nav.rows.current[row]; } else { row_pos = -1; } // APPLY POSITION TO MARKER if (is_animated) { VMM.Lib.stop(era.content); VMM.Lib.stop(era.text_content); VMM.Lib.animate(era.content, config.duration/2, config.ease, {"top": row_pos, "left": pos.begin, "width": era_length, "height":era_height}); VMM.Lib.animate(era.text_content, config.duration/2, config.ease, {"left": pos.begin}); } else { VMM.Lib.stop(era.content); VMM.Lib.stop(era.text_content); VMM.Lib.css(era.content, "left", pos.begin); VMM.Lib.css(era.content, "width", era_length); VMM.Lib.css(era.content, "height", era_height); VMM.Lib.css(era.content, "top", row_pos); VMM.Lib.css(era.text_content, "left", pos.begin); } } } function positionInterval(the_main_element, the_intervals, is_animated, is_minor) { var last_position = 0, last_position_major = 0, //in_view_margin = (config.nav.minor_width/config.nav.multiplier.current)/2, in_view_margin = config.width, in_view = { left: timenav_pos.visible.left - in_view_margin, right: timenav_pos.visible.right + in_view_margin } not_too_many = true, i = 0; config.nav.minor_left = 0; if (the_intervals.length > 100) { not_too_many = false; trace("TOO MANY " + the_intervals.length); } for(i = 0; i < the_intervals.length; i++) { var _interval = the_intervals[i].element, _interval_date = the_intervals[i].date, _interval_visible = the_intervals[i].visible, _pos = positionOnTimeline(interval, the_intervals[i].relative_pos), pos = _pos.begin, _animation = the_intervals[i].animation, is_visible = true, is_in_view = false, pos_offset = 50; _animation.pos = pos; _animation.animate = false; if (Math.abs(pos) >= in_view.left && Math.abs(pos) <= in_view.right ) { is_in_view = true; } if (true) { // CONDENSE WHAT IS DISPLAYED if (config.nav.multiplier.current > 16 && is_minor) { is_visible = false; } else { if ((pos - last_position) < 65 ) { if ((pos - last_position) < 35 ) { if (i%4 == 0) { if (pos == 0) { is_visible = false; } } else { is_visible = false; } } else { if (!VMM.Util.isEven(i)) { is_visible = false; } } } } if (is_visible) { if (the_intervals[i].is_detached) { VMM.Lib.append(the_main_element, _interval); the_intervals[i].is_detached = false; } } else { the_intervals[i].is_detached = true; VMM.Lib.detach(_interval); } if (_interval_visible) { if (!is_visible) { _animation.opacity = "0"; if (is_animated && not_too_many) { _animation.animate = true; } the_intervals[i].interval_visible = false; } else { _animation.opacity = "100"; if (is_animated && is_in_view) { _animation.animate = true; } } } else { _animation.opacity = "100"; if (is_visible) { if (is_animated && not_too_many) { _animation.animate = true; } else { if (is_animated && is_in_view) { _animation.animate = true; } } the_intervals[i].interval_visible = true; } else { if (is_animated && not_too_many) { _animation.animate = true; } } } last_position = pos; if (pos > config.nav.minor_width) { config.nav.minor_width = pos; } if (pos < config.nav.minor_left) { config.nav.minor_left = pos; } } if (_animation.animate) { VMM.Lib.animate(_interval, config.duration/2, config.ease, {opacity: _animation.opacity, left: _animation.pos}); } else { VMM.Lib.css(_interval, "opacity", _animation.opacity); VMM.Lib.css(_interval, "left", pos); } } config.nav.constraint.right_min = -(config.nav.minor_width)+(config.width); config.nav.constraint.right = config.nav.constraint.right_min + (config.width/2); VMM.Lib.css($timeintervalminor_minor, "left", config.nav.minor_left - (config.width)/2); VMM.Lib.width($timeintervalminor_minor, (config.nav.minor_width)+(config.width) + Math.abs(config.nav.minor_left) ); } /* Interval Elements ================================================== */ function createIntervalElements(_interval, _array, _element_parent) { var inc_time = 0, _first_run = true, _last_pos = 0, _largest_pos = 0, _timezone_offset, _first_date, _last_date, int_number = Math.ceil(_interval.number) + 2, firefox = { flag: false, offset: 0 }, i = 0; VMM.attachElement(_element_parent, ""); _interval.date = new Date(data[0].startdate.getFullYear(), 0, 1, 0,0,0); _timezone_offset = _interval.date.getTimezoneOffset(); for(i = 0; i < int_number; i++) { trace(_interval.type); var _is_year = false, int_obj = { element: VMM.appendAndGetElement(_element_parent, "
", _interval.classname), date: new Date(data[0].startdate.getFullYear(), 0, 1, 0,0,0), visible: false, date_string: "", type: _interval.interval_type, relative_pos: 0, is_detached: false, animation: { animate: false, pos: "", opacity: "100" } }; if (_interval.type == "eon") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 500000000) * 500000000; } int_obj.date.setFullYear(_first_date + (inc_time * 500000000)); _is_year = true; } else if (_interval.type == "era") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 100000000) * 100000000; } int_obj.date.setFullYear(_first_date + (inc_time * 100000000)); _is_year = true; } else if (_interval.type == "epoch") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 10000000) * 10000000 } int_obj.date.setFullYear(_first_date + (inc_time * 10000000)); _is_year = true; } else if (_interval.type == "age") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 1000000) * 1000000 } int_obj.date.setFullYear(_first_date + (inc_time * 1000000)); _is_year = true; } else if (_interval.type == "millenium") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 1000) * 1000; } int_obj.date.setFullYear(_first_date + (inc_time * 1000)); _is_year = true; } else if (_interval.type == "century") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 100) * 100 } int_obj.date.setFullYear(_first_date + (inc_time * 100)); _is_year = true; } else if (_interval.type == "decade") { if (_first_run) { _first_date = Math.floor(data[0].startdate.getFullYear() / 10) * 10; } int_obj.date.setFullYear(_first_date + (inc_time * 10)); _is_year = true; } else if (_interval.type == "year") { if (_first_run) { _first_date = data[0].startdate.getFullYear(); } int_obj.date.setFullYear(_first_date + inc_time); _is_year = true; } else if (_interval.type == "month") { if (_first_run) { _first_date = data[0].startdate.getMonth(); } int_obj.date.setMonth(_first_date + inc_time); } else if (_interval.type == "week") { if (_first_run) { _first_date = data[0].startdate.getMonth(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(_first_date + (inc_time * 7) ); } else if (_interval.type == "day") { if (_first_run) { _first_date = data[0].startdate.getDate(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(_first_date + inc_time); } else if (_interval.type == "hour") { if (_first_run) { _first_date = data[0].startdate.getHours(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(data[0].startdate.getDate()); int_obj.date.setHours(_first_date + inc_time); } else if (_interval.type == "minute") { if (_first_run) { _first_date = data[0].startdate.getMinutes(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(data[0].startdate.getDate()); int_obj.date.setHours(data[0].startdate.getHours()); int_obj.date.setMinutes(_first_date + inc_time); } else if (_interval.type == "second") { if (_first_run) { _first_date = data[0].startdate.getSeconds(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(data[0].startdate.getDate()); int_obj.date.setHours(data[0].startdate.getHours()); int_obj.date.setMinutes(data[0].startdate.getMinutes()); int_obj.date.setSeconds(_first_date + inc_time); } else if (_interval.type == "millisecond") { if (_first_run) { _first_date = data[0].startdate.getMilliseconds(); } int_obj.date.setMonth(data[0].startdate.getMonth()); int_obj.date.setDate(data[0].startdate.getDate()); int_obj.date.setHours(data[0].startdate.getHours()); int_obj.date.setMinutes(data[0].startdate.getMinutes()); int_obj.date.setSeconds(data[0].startdate.getSeconds()); int_obj.date.setMilliseconds(_first_date + inc_time); } // FIX WEIRD FIREFOX BUG FOR GMT TIME FORMATTING if (VMM.Browser.browser == "Firefox") { if (int_obj.date.getFullYear() == "1970" && int_obj.date.getTimezoneOffset() != _timezone_offset) { trace("FIREFOX 1970 TIMEZONE OFFSET " + int_obj.date.getTimezoneOffset() + " SHOULD BE " + _timezone_offset); trace(_interval.type + " " + _interval.date); // try and fix firefox bug, if not the flag will catch it firefox.offset = (int_obj.date.getTimezoneOffset()/60); firefox.flag = true; int_obj.date.setHours(int_obj.date.getHours() + firefox.offset ); } else if (firefox.flag) { // catch the bug the second time around firefox.flag = false; int_obj.date.setHours(int_obj.date.getHours() + firefox.offset ); if (_is_year) { firefox.flag = true; } } } if (_is_year) { if ( int_obj.date.getFullYear() < 0 ) { int_obj.date_string = Math.abs( int_obj.date.getFullYear() ).toString() + " B.C."; } else { int_obj.date_string = int_obj.date.getFullYear(); } } else { int_obj.date_string = VMM.Date.prettyDate(int_obj.date, true); } // Increment Time inc_time = inc_time + 1; // No longer first run _first_run = false; int_obj.relative_pos = positionRelative(interval, int_obj.date); _last_pos = int_obj.relative_pos.begin; if (int_obj.relative_pos.begin > _largest_pos) { _largest_pos = int_obj.relative_pos.begin; } // Add the time string to the element and position it. VMM.appendElement(int_obj.element, int_obj.date_string); VMM.Lib.css(int_obj.element, "text-indent", -(VMM.Lib.width(int_obj.element)/2)); VMM.Lib.css(int_obj.element, "opacity", "0"); // add the interval element to the array _array.push(int_obj); } VMM.Lib.width($timeintervalminor_minor, _largest_pos); positionInterval(_element_parent, _array); } /* BUILD ================================================== */ function build() { var i = 0, j = 0; VMM.attachElement(layout, ""); $timenav = VMM.appendAndGetElement(layout, "
", "timenav"); $content = VMM.appendAndGetElement($timenav, "
", "content"); $time = VMM.appendAndGetElement($timenav, "
", "time"); $timeintervalminor = VMM.appendAndGetElement($time, "
", "time-interval-minor"); $timeintervalminor_minor = VMM.appendAndGetElement($timeintervalminor, "
", "minor"); $timeintervalmajor = VMM.appendAndGetElement($time, "
", "time-interval-major"); $timeinterval = VMM.appendAndGetElement($time, "
", "time-interval"); $timebackground = VMM.appendAndGetElement(layout, "
", "timenav-background"); $timenavline = VMM.appendAndGetElement($timebackground, "
", "timenav-line"); $timenavindicator = VMM.appendAndGetElement($timebackground, "
", "timenav-indicator"); $timeintervalbackground = VMM.appendAndGetElement($timebackground, "
", "timenav-interval-background", "
"); $toolbar = VMM.appendAndGetElement(layout, "
", "vco-toolbar"); buildInterval(); buildMarkers(); buildEras(); calculateMultiplier(); positionMarkers(false); positionEras(); positionInterval($timeinterval, interval_array, false, true); positionInterval($timeintervalmajor, interval_major_array); if (config.start_page) { $backhome = VMM.appendAndGetElement($toolbar, "
", "back-home", "
"); VMM.bindEvent(".back-home", onBackHome, "click"); VMM.Lib.attribute($backhome, "title", VMM.master_config.language.messages.return_to_title); VMM.Lib.attribute($backhome, "rel", "tooltip"); } // MAKE TIMELINE DRAGGABLE/TOUCHABLE $dragslide = new VMM.DragSlider; $dragslide.createPanel(layout, $timenav, config.nav.constraint, config.touch); if (config.touch && config.start_page) { VMM.Lib.addClass($toolbar, "touch"); VMM.Lib.css($toolbar, "top", 55); VMM.Lib.css($toolbar, "left", 10); } else { if (config.start_page) { VMM.Lib.css($toolbar, "top", 27); } $zoomin = VMM.appendAndGetElement($toolbar, "
", "zoom-in", "
"); $zoomout = VMM.appendAndGetElement($toolbar, "
", "zoom-out", "
"); // ZOOM EVENTS VMM.bindEvent($zoomin, onZoomIn, "click"); VMM.bindEvent($zoomout, onZoomOut, "click"); // TOOLTIP VMM.Lib.attribute($zoomin, "title", VMM.master_config.language.messages.expand_timeline); VMM.Lib.attribute($zoomin, "rel", "tooltip"); VMM.Lib.attribute($zoomout, "title", VMM.master_config.language.messages.contract_timeline); VMM.Lib.attribute($zoomout, "rel", "tooltip"); $toolbar.tooltip({selector: "div[rel=tooltip]", placement: "right"}); // MOUSE EVENTS VMM.bindEvent(layout, onMouseScroll, 'DOMMouseScroll'); VMM.bindEvent(layout, onMouseScroll, 'mousewheel'); } // USER CONFIGURABLE ADJUSTMENT TO DEFAULT ZOOM if (config.nav.zoom.adjust != 0) { if (config.nav.zoom.adjust < 0) { for(i = 0; i < Math.abs(config.nav.zoom.adjust); i++) { onZoomOut(); } } else { for(j = 0; j < config.nav.zoom.adjust; j++) { onZoomIn(); } } } //VMM.fireEvent(layout, "LOADED"); _active = true; reSize(true); VMM.fireEvent(layout, "LOADED"); }; function buildInterval() { var i = 0, j = 0; // CALCULATE INTERVAL timespan = getDateFractions((data[data.length - 1].enddate) - (data[0].startdate), true); trace(timespan); calculateInterval(); /* DETERMINE DEFAULT INTERVAL TYPE millenium, ages, epoch, era and eon are not working yet ================================================== */ if (timespan.centuries > data.length / config.nav.density) { interval = interval_calc.century; interval_major = interval_calc.millenium; interval_macro = interval_calc.decade; } else if (timespan.decades > data.length / config.nav.density) { interval = interval_calc.decade; interval_major = interval_calc.century; interval_macro = interval_calc.year; } else if (timespan.years > data.length / config.nav.density) { interval = interval_calc.year; interval_major = interval_calc.decade; interval_macro = interval_calc.month; } else if (timespan.months > data.length / config.nav.density) { interval = interval_calc.month; interval_major = interval_calc.year; interval_macro = interval_calc.day; } else if (timespan.days > data.length / config.nav.density) { interval = interval_calc.day; interval_major = interval_calc.month; interval_macro = interval_calc.hour; } else if (timespan.hours > data.length / config.nav.density) { interval = interval_calc.hour; interval_major = interval_calc.day; interval_macro = interval_calc.minute; } else if (timespan.minutes > data.length / config.nav.density) { interval = interval_calc.minute; interval_major = interval_calc.hour; interval_macro = interval_calc.second; } else if (timespan.seconds > data.length / config.nav.density) { interval = interval_calc.second; interval_major = interval_calc.minute; interval_macro = interval_calc.second; } else { trace("NO IDEA WHAT THE TYPE SHOULD BE"); interval = interval_calc.day; interval_major = interval_calc.month; interval_macro = interval_calc.hour; } trace("INTERVAL TYPE: " + interval.type); trace("INTERVAL MAJOR TYPE: " + interval_major.type); createIntervalElements(interval, interval_array, $timeinterval); createIntervalElements(interval_major, interval_major_array, $timeintervalmajor); // Cleanup duplicate interval elements between normal and major for(i = 0; i < interval_array.length; i++) { for(j = 0; j < interval_major_array.length; j++) { if (interval_array[i].date_string == interval_major_array[j].date_string) { VMM.attachElement(interval_array[i].element, ""); } } } } function buildMarkers() { var row = 2, lpos = 0, row_depth = 0, i = 0, k = 0, l = 0; markers = []; era_markers = []; for(i = 0; i < data.length; i++) { var _marker, _marker_flag, _marker_content, _marker_dot, _marker_line, _marker_line_event, _marker_obj, _marker_title = "", has_title = false; _marker = VMM.appendAndGetElement($content, "
", "marker"); _marker_flag = VMM.appendAndGetElement(_marker, "
", "flag"); _marker_content = VMM.appendAndGetElement(_marker_flag, "
", "flag-content"); _marker_dot = VMM.appendAndGetElement(_marker, "
", "dot"); _marker_line = VMM.appendAndGetElement(_marker, "
", "line"); _marker_line_event = VMM.appendAndGetElement(_marker_line, "
", "event-line"); _marker_relative_pos = positionRelative(interval, data[i].startdate, data[i].enddate); _marker_thumb = ""; // THUMBNAIL if (data[i].asset != null && data[i].asset != "") { VMM.appendElement(_marker_content, VMM.MediaElement.thumbnail(data[i].asset, 24, 24, data[i].uniqueid)); } else { VMM.appendElement(_marker_content, "
"); } // ADD DATE AND TITLE if (data[i].title == "" || data[i].title == " " ) { trace("TITLE NOTHING") if (typeof data[i].slug != 'undefined' && data[i].slug != "") { trace("SLUG") _marker_title = VMM.Util.untagify(data[i].slug); has_title = true; } else { var m = VMM.MediaType(data[i].asset.media); if (m.type == "quote" || m.type == "unknown") { _marker_title = VMM.Util.untagify(m.id); has_title = true; } else { has_title = false; } } } else if (data[i].title != "" || data[i].title != " ") { trace(data[i].title) _marker_title = VMM.Util.untagify(data[i].title); has_title = true; } else { trace("TITLE SLUG NOT FOUND " + data[i].slug) } if (has_title) { VMM.appendElement(_marker_content, "

" + _marker_title + "

"); } else { VMM.appendElement(_marker_content, "

" + _marker_title + "

"); VMM.appendElement(_marker_content, "

" + _marker_title + "

"); } // ADD ID VMM.Lib.attr(_marker, "id", ( "marker_" + data[i].uniqueid).toString() ); // MARKER CLICK VMM.bindEvent(_marker_flag, onMarkerClick, "", {number: i}); VMM.bindEvent(_marker_flag, onMarkerHover, "mouseenter mouseleave", {number: i, elem:_marker_flag}); _marker_obj = { marker: _marker, flag: _marker_flag, lineevent: _marker_line_event, type: "marker", full: true, relative_pos: _marker_relative_pos, tag: data[i].tag, pos_left: 0 }; if (data[i].type == "start") { trace("BUILD MARKER HAS START PAGE"); config.start_page = true; _marker_obj.type = "start"; } if (data[i].type == "storify") { _marker_obj.type = "storify"; } if (data[i].tag) { tags.push(data[i].tag); } markers.push(_marker_obj); } // CREATE TAGS tags = VMM.Util.deDupeArray(tags); if (tags.length > 3) { config.nav.rows.current = config.nav.rows.half; } else { config.nav.rows.current = config.nav.rows.full; } for(k = 0; k < tags.length; k++) { if (k < config.nav.rows.current.length) { var tag_element = VMM.appendAndGetElement($timebackground, "
", "timenav-tag"); VMM.Lib.addClass(tag_element, "timenav-tag-row-" + (k+1)); if (tags.length > 3) { VMM.Lib.addClass(tag_element, "timenav-tag-size-half"); } else { VMM.Lib.addClass(tag_element, "timenav-tag-size-full"); } VMM.appendElement(tag_element, "

" + tags[k] + "

"); } } // RESIZE FLAGS IF NEEDED if (tags.length > 3) { for(l = 0; l < markers.length; l++) { VMM.Lib.addClass(markers[l].flag, "flag-small"); markers[l].full = false; } } } function buildEras() { var number_of_colors = 6, current_color = 0, j = 0; // CREATE ERAS for(j = 0; j < eras.length; j++) { var era = { content: VMM.appendAndGetElement($content, "
", "era"), text_content: VMM.appendAndGetElement($timeinterval, "
", "era"), startdate: VMM.Date.parse(eras[j].startDate), enddate: VMM.Date.parse(eras[j].endDate), title: eras[j].headline, uniqueid: VMM.Util.unique_ID(6), tag: "", relative_pos: "" }, st = VMM.Date.prettyDate(era.startdate), en = VMM.Date.prettyDate(era.enddate), era_text = "
 
"; if (typeof eras[j].tag != "undefined") { era.tag = eras[j].tag; } era.relative_pos = positionRelative(interval, era.startdate, era.enddate); VMM.Lib.attr(era.content, "id", era.uniqueid); VMM.Lib.attr(era.text_content, "id", era.uniqueid + "_text"); // Background Color VMM.Lib.addClass(era.content, "era"+(current_color+1)); VMM.Lib.addClass(era.text_content, "era"+(current_color+1)); if (current_color < number_of_colors) { current_color++; } else { current_color = 0; } VMM.appendElement(era.content, era_text); VMM.appendElement(era.text_content, VMM.Util.unlinkify(era.title)); era_markers.push(era); } } }; }