All the data is grabbed from a html table saved in a separate pen via ajax. Easily updatable - new events can be added by anyone who can copy and paste in html.
A Pen by chris-creditdesign on CodePen.
All the data is grabbed from a html table saved in a separate pen via ajax. Easily updatable - new events can be added by anyone who can copy and paste in html.
A Pen by chris-creditdesign on CodePen.
<div class="outerwrapper"> | |
<div class="timeline"> | |
<div class="timeline-header"> | |
<h3>INTERACTIVE:</h3> | |
<h2><span class="timeline-heading"></span></h2> | |
<p class="timeline-standfirst"></p> | |
</div> | |
<div class="tooltip"> | |
<p></p> | |
</div> | |
</div> <!-- timeline --> | |
<div class="info-box"> | |
<div class="panel"></div> | |
</div> | |
</div> <!-- outerwrapper --> |
/* An array to store all the data */ | |
var items = []; | |
$.ajax({ | |
url: "http://codepen.io/chris-creditdesign/pen/87c2848937b6962f4efd2a67e5ea2031.html", | |
// url: "table-nih.html", | |
dataType: 'text', | |
success: function(data) { | |
/* Helper function to format and parse date from data */ | |
function getDate(d) { | |
/* If d is a number or a string in the format Day Month Year | |
process it as normal. Other wise presume that it may be a string | |
in the format Month Year and add 1 to the start so that Firefox | |
and safari can parse the date */ | |
if (typeof d === "number") { | |
return new Date(d); | |
} else if (Date.parse(d)) { | |
return new Date(d); | |
} else { | |
return new Date("1 " + d); | |
} | |
} | |
var fullData = $(data); | |
var table = $(data).find("table tbody tr"); | |
/* Grab the tables headline and caption so that we can reproduce them in the widget */ | |
var headline = $(fullData).find("h2.table-heading").text(); | |
var standfirst = $(data).find("table caption p").text(); | |
/* Hides the table and shows the SVG if javascript is enabled */ | |
// $("h2:contains('Dogs at work')").parent("section").parent("div").css({"display":"none"}); | |
// $("h2:contains('Dogs at work') + table").css({"width":"630px"}); | |
$(".outerwrapper span.timeline-heading").text(headline); | |
$(".outerwrapper p.timeline-standfirst").text(standfirst); | |
// $(".outerwrapper").css({"display":"block"}); | |
/* Push an object into the items array for each table row/point on the timeline */ | |
for (var i = 0; i < $(table).length; i++) { | |
var newObject = {}; | |
items.push(newObject); | |
}; | |
/* Add a prorerty to the objects for each column in the table/bit of info we want to show | |
i.e date, headline, the text, image link and credit */ | |
for (var i = 0; i < $(table).length; i++) { | |
var dateStart = $(table).eq(i).children('td').eq(0).html(); | |
var dateEnd; | |
if ($(table).eq(i).children('td').eq(1).html() === " ") { | |
dateEnd = $(table).eq(i).children('td').eq(0).html(); | |
} else { | |
dateEnd = $(table).eq(i).children('td').eq(1).html(); | |
} | |
items[i].dateStart = dateStart; | |
items[i].dateEnd = dateEnd; | |
items[i].date1 = getDate(dateStart); | |
items[i].date2 = getDate(dateEnd); | |
if ($(table).eq(i).children('td').eq(2).html() !== " ") { | |
items[i].headline = $(table).eq(i).children('td').eq(2).html(); | |
} | |
if ($(table).eq(i).children('td').eq(3).html() !== " ") { | |
items[i].text = $(table).eq(i).children('td').eq(3).html(); | |
} | |
if ($(table).eq(i).children('td').eq(4).html() !== " ") { | |
items[i].link = $(table).eq(i).children('td').eq(4).html(); | |
} | |
if ($(table).eq(i).children('td').eq(5).html() !== " ") { | |
items[i].img = $(table).eq(i).children('td').eq(5).html(); | |
items[i].credit = $(table).eq(i).children('td').eq(6).html(); | |
} | |
}; | |
console.log(items); | |
/* Insert an .event div for each event */ | |
for (var i = 0; i < items.length; i++) { | |
$(".outerwrapper .info-box .panel").append('<div class="event-' + i + '"></div>'); | |
}; | |
for (var i = 0; i < $('.outerwrapper div[class^="event"]').length; i++) { | |
if (items[i].img) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<span class="timeline-img">' + items[i].img + '</span>'); | |
} | |
if (items[i].date1 < items[i].date2) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<h3>' + items[i].dateStart + ' - ' + items[i].dateEnd + '</h3>'); | |
} else { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<h3>' + items[i].dateStart + '</h3>'); | |
} | |
if (items[i].headline) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<h4>' + items[i].headline + ' (' + (i + 1) + ' of ' + items.length + ')</h4>'); | |
} else { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<h4> (' + (i + 1) + ' of ' + items.length + ')</h4>'); | |
} | |
if (items[i].text) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<p>' + items[i].text + '</p>'); | |
} | |
if (items[i].link) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<p>' + items[i].link + '</p>'); | |
} | |
if (items[i].img) { | |
$('.outerwrapper div[class="event-' + i + '"]') | |
.append('<p class="credit">PICTURE CREDIT: ' + items[i].credit + '</p>') | |
} | |
}; | |
var eventWidth = $('.outerwrapper .info-box').width(); | |
var position = 0; | |
var panelWidth = eventWidth * items.length; | |
$(".outerwrapper .info-box .panel").css({ | |
"width": panelWidth + "px" | |
}); | |
/* Load D3 */ | |
/* All of the D3/svg code is contained within the callback function */ | |
/* Loading D3 via a html script tag into ie6-8 will to cause a runtime error */ | |
$.getScript("http://d3js.org/d3.v3.min.js", function() { | |
// $.getScript("http://d3js.org/d3.v3.min.js", function() { | |
/* Define the dimensions of the SVG */ | |
var duration = 200; | |
var marginTop = 5; | |
var marginRight = 0; | |
var marginBottom = 40; | |
var marginLeft = 0; | |
var padding = 2; | |
var width = 630 - marginRight - marginLeft; | |
var height = 290 - marginTop - marginBottom; | |
var miniHeight = 75; | |
var mainHeight = height - miniHeight - 50; | |
var zoom = 1; | |
var maxZoom = 10; | |
var zoomIncrement = 1; | |
/* A global variable to control which event/location to show */ | |
var counter = 0; | |
/* A global variable to control the amout of ticks visible */ | |
var ticks = 8; | |
/* Find the earliest and latest time in the range */ | |
var timeFirst = d3.min(items, function(d) { | |
return d.date1; | |
}); | |
var timeLast = d3.max(items, function(d) { | |
return d.date2; | |
}); | |
/* Work out the time span of the whole timeline in miliseconds plus one tenth of this value */ | |
var timeDiff = timeLast - timeFirst; | |
timeDiff = timeDiff + (timeDiff * 0.1); | |
/* Extend the time range before the first date and after the last date | |
to make for a more attractive timeline */ | |
var timeBegin = getDate(items[counter].date1.getTime() - timeDiff); | |
var timeEnd = getDate(items[counter].date1.getTime() + timeDiff); | |
/* Scales */ | |
var x = d3.time.scale() | |
.domain([timeBegin, timeEnd]) | |
.range([0, width]); | |
/* Create the SVG and its elements */ | |
var chart = d3.select(".timeline") | |
.append("svg") | |
.attr("width", width + marginRight + marginLeft) | |
.attr("height", height + marginTop + marginBottom) | |
.attr("class", "chart"); | |
/* Draw the four icons for zooming and moving through the time line as well as their enclosing | |
rects. Add functionality for hover and click. */ | |
var zoomInIcon = chart.append("path") | |
.attr("d", "M22.646,19.307c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127l3.535-3.537L22.646,19.307zM13.688,20.369c-3.582-0.008-6.478-2.904-6.484-6.484c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486C20.165,17.465,17.267,20.361,13.688,20.369zM15.687,9.051h-4v2.833H8.854v4.001h2.833v2.833h4v-2.834h2.832v-3.999h-2.833V9.051z") | |
.style("pointer-events", "none") | |
.attr("transform", "translate(5,60), scale(1.25)"); | |
var zoomInButton = chart.append("rect") | |
.attr("width", 50) | |
.attr("height", 50) | |
.style("fill", colourBackground[4]) | |
.style("opacity", 0.2) | |
.attr("transform", "translate(0,55)") | |
.style("cursor", "pointer") | |
.on("click", function(e) { | |
if (zoom < maxZoom) { | |
zoom += zoomIncrement; | |
showLocation(); | |
}; | |
d3.event.preventDefault(); | |
return false; | |
}) | |
.on("mouseover", function() { | |
if (zoom < maxZoom) { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.5); | |
}; | |
}) | |
.on("mouseout", function() { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.2); | |
}); | |
var zoomOutIcon = chart.append("path") | |
.attr("d", "M22.646,19.307c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127l3.535-3.537L22.646,19.307zM13.688,20.369c-3.582-0.008-6.478-2.904-6.484-6.484c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486C20.165,17.465,17.267,20.361,13.688,20.369zM8.854,11.884v4.001l9.665-0.001v-3.999L8.854,11.884z") | |
.style("pointer-events", "none") | |
.attr("transform", "translate(55,60), scale(1.25)"); | |
var zoomOutButton = chart.append("rect") | |
.attr("width", 50) | |
.attr("height", 50) | |
.style("fill", colourBackground[4]) | |
.style("opacity", 0.2) | |
.attr("transform", "translate(50,55)") | |
.style("cursor", "pointer") | |
.on("click", function(e) { | |
if (zoom > 1) { | |
zoom -= zoomIncrement; | |
showLocation(); | |
}; | |
d3.event.preventDefault(); | |
return false; | |
}) | |
.on("mouseover", function() { | |
if (zoom > 1) { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.5); | |
}; | |
}) | |
.on("mouseout", function() { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.2); | |
}); | |
var leftIcon = chart.append("path") | |
.attr("d", "M20.834,8.037L9.641,14.5c-1.43,0.824-1.43,2.175,0,3l11.193,6.463c1.429,0.826,2.598,0.15,2.598-1.5V9.537C23.432,7.887,22.263,7.211,20.834,8.037z") | |
.style("pointer-events", "none") | |
.attr("transform", "translate(0,0), scale(1.5)"); | |
var leftButton = chart.append("rect") | |
.attr("width", 50) | |
.attr("height", 50) | |
.style("fill", colourBackground[4]) | |
.style("opacity", 0.2) | |
.attr("transform", "translate(0,0)") | |
.style("cursor", "pointer") | |
.on("click", function(e) { | |
if (counter > 0) { | |
counter -= 1; | |
}; | |
showLocation(); | |
d3.event.preventDefault(); | |
return false; | |
}) | |
.on("mouseover", function() { | |
if (counter > 0) { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.5); | |
}; | |
}) | |
.on("mouseout", function() { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.2); | |
}); | |
var rightIcon = chart.append("path") | |
.attr("d", "M11.166,23.963L22.359,17.5c1.43-0.824,1.43-2.175,0-3L11.166,8.037c-1.429-0.826-2.598-0.15-2.598,1.5v12.926C8.568,24.113,9.737,24.789,11.166,23.963z") | |
.style("pointer-events", "none") | |
.attr("transform", "translate(50,0), scale(1.5)"); | |
var rightButton = chart.append("rect") | |
.attr("width", 50) | |
.attr("height", 50) | |
.style("fill", colourBackground[4]) | |
.style("opacity", 0.2) | |
.attr("transform", "translate(50,0)") | |
.style("cursor", "pointer") | |
.on("click", function(e) { | |
if (counter < (items.length - 1)) { | |
counter += 1; | |
}; | |
showLocation(); | |
d3.event.preventDefault(); | |
return false; | |
}) | |
.on("mouseover", function() { | |
if (counter < (items.length - 1)) { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.5); | |
}; | |
}) | |
.on("mouseout", function() { | |
d3.select(this).transition() | |
.duration(duration) | |
.style("opacity", 0.2); | |
}); | |
/* Prepare a cliping path to stop the locations and scales breaking spilling over the edges | |
of the SVG in IE */ | |
chart.append("defs").append("clipPath") | |
.attr("id", "clip") | |
.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", width) | |
.attr("height", height + marginTop + marginBottom); | |
chart.append("g") | |
.append("rect") | |
.attr("x", 0) | |
.attr("y", (height - miniHeight)) | |
.attr("width", width) | |
.attr("height", miniHeight) | |
.attr("fill", colourBackground[2]) | |
.style("opacity", 0.5); | |
var miniHolder = chart.append("g") | |
.attr("clip-path", "url(#clip)"); | |
var mini = miniHolder.append("g") | |
.attr("width", width) | |
.attr("height", miniHeight) | |
.attr("class", "mini") | |
.attr("transform", "translate(0," + (height - miniHeight) + ")") | |
/* create three seperate x axis for Year, Month and Day based on the same x scale */ | |
var xYearAxis = d3.svg.axis() | |
.scale(x) | |
.tickSize(15, 0) | |
.ticks(d3.time.years, 1) | |
.tickFormat(d3.time.format('%Y')) | |
.orient('top'); | |
var yearAxis = mini.append('g') | |
.attr('class', 'year-axis') | |
.call(xYearAxis); | |
var xMonthAxis = d3.svg.axis() | |
.scale(x) | |
.tickSize(-miniHeight, 0) | |
.orient('top'); | |
var monthAxis = mini.append('g') | |
.attr('class', 'axis') | |
.call(xMonthAxis); | |
var xDayAxis = d3.svg.axis() | |
.scale(x) | |
.tickSize(10, 0) | |
.tickFormat(function(d) { | |
return ''; | |
}) | |
.orient('bottom'); | |
var dayAxis = mini.append('g') | |
.attr('class', 'axis') | |
.attr("transform", "translate(0," + (miniHeight - 10) + ")") | |
.call(xDayAxis); | |
/* draw the static triangle to act as a pointer */ | |
chart.append("path") | |
.attr("d", "M10,0 L20,20 L0,20z") | |
.style("fill", colourBorder[0]) | |
.style("pointer-events", "none") | |
.attr("transform", "translate(" + ((width / 2) - 10) + "," + height + ")"); | |
/* Add rect for each point on the timeline */ | |
var locations = mini.append("g").selectAll("rect") | |
.data(items) | |
.enter() | |
.append("rect") | |
.attr("class", function(d, i) { | |
if (i === counter) { | |
return "locations selected"; | |
} else { | |
return "locations"; | |
}; | |
}) | |
.attr("x", function(d, i) { | |
return x(d.date1); | |
}) | |
.attr("y", function(d, i) { | |
/* Work out if the first date of the current range overlaps the last date of the previous | |
if so move the current rect down so that there is no overlap*/ | |
var prev = 0; | |
if (i > 0) { | |
prev = i - 1; | |
} | |
if (i === 0) { | |
return 0; | |
} else if (items[prev].date2 < items[i].date1) { | |
return 0; | |
} else { | |
return (miniHeight - 10) / 2; | |
} | |
}) | |
.attr("width", function(d) { | |
if (d.date1 < d.date2) { | |
/* decide the width of the rect based on the range of dates */ | |
return x(d.date2) - x(d.date1); | |
} else { | |
/* if no end date is specified add 86,400,000 milliseconds (1 day) to the first | |
date to create a span of time for the width | |
but make sure that it is at least 4 px wide */ | |
var thisWidth = x(getDate(d.date1.getTime() + 86400000)) - x(d.date1); | |
if (thisWidth < 4) { | |
return 4; | |
} else { | |
return thisWidth; | |
} | |
} | |
}) | |
.attr("height", function(d, i) { | |
/* Work out if the first date of the current range overlaps the last date of the previous | |
if so half the height of the block to accomadate */ | |
var prev = 0; | |
var next; | |
if (i > 0) { | |
prev = i - 1; | |
} | |
if (i < items.length - 1) { | |
next = i + 1 | |
} else { | |
next = items.length - 1; | |
} | |
if (prev > 0) { | |
if (items[i].date2 > items[next].date1) { | |
return (miniHeight - 10) / 2; | |
} else if (items[prev].date2 > items[i].date1) { | |
return (miniHeight - 10) / 2; | |
} else { | |
return (miniHeight - 10); | |
} | |
} else { | |
return (miniHeight - 10); | |
} | |
}) | |
.on("mouseover", function(d, i) { | |
if (d.date1 < d.date2) { | |
d3.select(".outerwrapper .timeline .tooltip") | |
.html("<p>" + d.dateStart + " - <br />" + d.dateEnd + "</p>"); | |
} else { | |
d3.select(".outerwrapper .timeline .tooltip") | |
.html("<p>" + d.dateStart + "</p>"); | |
} | |
var eventLeft = parseInt(d3.select(this).attr("x")); | |
var eventWidth = parseInt(d3.select(this).attr("width")); | |
var eventTop = parseInt(d3.select(this).attr("y")); | |
var tooltipHeight = parseInt($(".outerwrapper .timeline .tooltip").css("height")); | |
$(".outerwrapper .timeline .tooltip") | |
.css({ | |
"left": eventLeft + (eventWidth / 2) + "px", | |
"top": 145 - (tooltipHeight - eventTop) + "px" | |
}); | |
$(".outerwrapper .timeline .tooltip").css({ | |
"opacity": 1, | |
"display": "block" | |
}); | |
}) | |
.on("mouseout", function() { | |
$(".outerwrapper .timeline .tooltip").css({ | |
"opacity": 0, | |
"display": "none" | |
}); | |
}) | |
.on("click", function(d, i) { | |
counter = i; | |
showLocation(); | |
$(".outerwrapper .timeline .tooltip").css({ | |
"opacity": 0, | |
"display": "none" | |
}); | |
d3.event.preventDefault(); | |
return false; | |
}) | |
/* Function to add the info for the next selected location | |
Adds the relevent content to info-box and provides a new value for xPosition | |
to center the timeline on the selected location*/ | |
function showLocation() { | |
position = eventWidth * counter; | |
$('.outerwrapper .info-box').animate({ | |
scrollLeft: position | |
}, duration); | |
/* Recalculate the start and end point of the time range based upon | |
the current location and the zoom level */ | |
timeBegin = getDate(items[counter].date1.getTime() - (timeDiff / zoom)); | |
timeEnd = getDate(items[counter].date1.getTime() + (timeDiff / zoom)); | |
/* Replace the values used in the x domain */ | |
x.domain([timeBegin, timeEnd]); | |
/* Adjust the ticks for each x axis depening on the time range */ | |
/* ticks for than 5 years, 157,788,000,000 milliseconds */ | |
if ((timeEnd - timeBegin) > 157788000000) { | |
xMonthAxis.ticks(d3.time.years, 1).tickFormat(function(d) { | |
return ''; | |
}); | |
xDayAxis.ticks(d3.time.years, 1); | |
} | |
/* ticks for than a year, 31,557,600,000 milliseconds */ | |
else if ((timeEnd - timeBegin) > 31557600000) { | |
xMonthAxis.ticks(d3.time.months, 3).tickFormat(d3.time.format('%d %b')); | |
xDayAxis.ticks(d3.time.months, 1); | |
} | |
/* ticks for than six months 31,557,600,000 milliseconds divided by 2 */ | |
else if ((timeEnd - timeBegin) > 15778800000) { | |
xMonthAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%d %b')); | |
xDayAxis.ticks(d3.time.weeks, 1); | |
} | |
/* ticks for than two months 31,557,600,000 milliseconds divided by 6 */ | |
else if ((timeEnd - timeBegin) > 5259600000) { | |
xMonthAxis.ticks(d3.time.months, 1).tickFormat(d3.time.format('%d %b')); | |
xDayAxis.ticks(d3.time.days, 1); | |
} | |
/* ticks for than a month 31,557,600,000 milliseconds divided by 12 */ | |
else if ((timeEnd - timeBegin) > 2629800000) { | |
xMonthAxis.ticks(d3.time.weeks, 1).tickFormat(d3.time.format('%d %b')); | |
xDayAxis.ticks(d3.time.days, 1); | |
} | |
/* ticks for a day */ | |
else { | |
xMonthAxis.ticks(d3.time.days, 4).tickFormat(d3.time.format('%d %b')); | |
xDayAxis.ticks(d3.time.days, 1); | |
} | |
/* Redraw each x axis based on the new domain */ | |
yearAxis.transition() | |
.duration(duration) | |
.call(xYearAxis); | |
monthAxis.transition() | |
.duration(duration) | |
.call(xMonthAxis); | |
dayAxis.transition() | |
.duration(duration) | |
.call(xDayAxis); | |
/* Give the selected location the class of 'selected' | |
then animate the locations to their new position based on the updated x scale */ | |
locations.classed("selected", false) | |
.attr("class", function(d, i) { | |
if (i === counter) { | |
return "locations selected"; | |
} else { | |
return "locations"; | |
}; | |
}) | |
.transition() | |
.duration(duration) | |
.attr("x", function(d, i) { | |
return x(d.date1); | |
}) | |
.attr("width", function(d) { | |
if (d.date1 < d.date2) { | |
/* decide the width of the rect based on the range of dates */ | |
return x(d.date2) - x(d.date1); | |
} else { | |
/* if no end date is specified add 86,400,000 milliseconds to the first | |
date to create a span of time for the width | |
but make sure that it is at least 4 px wide */ | |
var thisWidth = x(getDate(d.date1.getTime() + 86400000)) - x(d.date1); | |
if (thisWidth < 4) { | |
return 4; | |
} else { | |
return thisWidth; | |
} | |
} | |
}); | |
/* Fade out the next/prev and zoom buttons when they are not available */ | |
switch (counter) { | |
case 0: | |
leftIcon.style("fill", colourText[7]); | |
rightIcon.style("fill", colourText[1]); | |
break; | |
case (items.length - 1): | |
leftIcon.style("fill", colourText[1]); | |
rightIcon.style("fill", colourText[7]); | |
break; | |
default: | |
leftIcon.style("fill", colourText[1]); | |
rightIcon.style("fill", colourText[1]); | |
break; | |
} | |
switch (zoom) { | |
case 1: | |
zoomInIcon.style("fill", colourText[1]); | |
zoomOutIcon.style("fill", colourText[7]); | |
break; | |
case maxZoom: | |
zoomInIcon.style("fill", colourText[7]); | |
zoomOutIcon.style("fill", colourText[1]); | |
break; | |
default: | |
zoomInIcon.style("fill", colourText[1]); | |
zoomOutIcon.style("fill", colourText[1]); | |
break; | |
} | |
} | |
/* Initial call of show position to adjust the timeline on page load */ | |
showLocation(); | |
}); /* End of getScript callback function */ | |
} | |
}); /* End of Ajax success function */ |
body { | |
color: #000000; | |
font-family: Verdana,arial,Helvetica,sans-serif; | |
font-size: 90%; | |
} | |
.outerwrapper { | |
/*display: none;*/ | |
width: 630px; | |
position: relative; | |
} | |
.outerwrapper .visually-hidden { | |
width:1px; | |
height:1px; | |
position: absolute !important; | |
clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ | |
clip: rect(1px, 1px, 1px, 1px); | |
} | |
.outerwrapper .timeline { | |
width: 630px; | |
height: 260px; | |
} | |
.outerwrapper .timeline-header { | |
position: absolute; | |
top: -4px; | |
left: 120px; | |
width: 500px; | |
height: 110px; | |
z-index: 10; | |
} | |
.outerwrapper .timeline-header h2 { | |
font-size: 1.3em; | |
margin: 0 0 1em 0; | |
color: #666; | |
} | |
.outerwrapper .timeline-header h3 { | |
margin: 0 0 0.5em 0; | |
color: #999; | |
} | |
.outerwrapper .info-box { | |
position: relative; | |
top: 0px; | |
width: 630px; | |
height: 320px; | |
opacity: 1; | |
border-top: 2px solid #999999; | |
border-bottom: 2px solid #999999; | |
z-index: 10; | |
background: white; | |
overflow: hidden; | |
} | |
.outerwrapper div[class^='event'] { | |
position: relative; | |
float: left; | |
width: 630px; | |
padding: 10px 0; | |
} | |
.outerwrapper .info-box div[class^='event'] h3 { | |
margin: 0 0 1em 5px; | |
color: #666; | |
} | |
.outerwrapper .info-box div[class^='event'] h4 { | |
margin: 0 0 0 5px; | |
color: #999; | |
font-style: italic; | |
} | |
.outerwrapper .info-box div[class^='event'] p { | |
margin: 0 0 0 5px; | |
} | |
.outerwrapper .info-box div[class^='event'] img { | |
float: right; | |
margin: 0 5px 0 10px; | |
max-width: 300px; | |
} | |
.outerwrapper .info-box div[class^='event'] a:before { | |
content:url(http://www.nature.com/polopoly_fs/7.7008.1350920391!/image/link.jpg); | |
} | |
.outerwrapper .info-box div[class^='event'] .credit { | |
margin: 0.8em 0 0 0; | |
} | |
.outerwrapper .info-box div[class^='event'] .credit a:before { | |
content:none; | |
} | |
.outerwrapper .tooltip | |
{ | |
display:none; | |
position: absolute; | |
top: 110px; | |
width: 135px; | |
z-index: 999; | |
margin-left: -75px; | |
padding: 10px; | |
background-color: #5E5E5E; | |
text-align:center; | |
opacity: 0; | |
-webkit-transition: opacity 0.3s ease; | |
-moz-transition: opacity 0.3s ease; | |
-o-transition: opacity 0.3s ease; | |
-ms-transition: opacity 0.3s ease; | |
transition: opacity 0.3s ease; | |
} | |
.outerwrapper .tooltip:after | |
{ | |
content: ""; | |
position:absolute; | |
z-index: 1000; | |
bottom: -8px; | |
left: 50%; | |
margin-left: -12px; | |
border-top: 10px solid #5E5E5E; | |
border-left: 10px solid transparent; | |
border-right: 10px solid transparent; | |
border-bottom: 0; | |
} | |
.outerwrapper .tooltip p { | |
margin: 0; | |
color: #FFF; | |
} | |
/* SVG | |
----------------------------------*/ | |
.outerwrapper svg text { | |
font: 13px sans-serif; | |
} | |
.outerwrapper svg .axis text, .outerwrapper svg .year-axis text { | |
font: 11px sans-serif; | |
} | |
.outerwrapper svg .axis path, .outerwrapper svg .year-axis path { | |
fill: none; | |
stroke: none; | |
} | |
.outerwrapper svg .axis line { | |
fill: none; | |
stroke: #999999; | |
shape-rendering: crispEdges; | |
} | |
.outerwrapper svg .year-axis line { | |
stroke: none; | |
} | |
.outerwrapper svg .locations { | |
fill: #999999; | |
cursor: pointer; | |
-webkit-transition: all 0.2s ease; | |
-moz-transition: all 0.2s ease; | |
-o-transition: all 0.2s ease; | |
-ms-transition: all 0.2s ease; | |
transition: all 0.2s ease; | |
} | |
.outerwrapper svg .locations:hover { | |
fill: #EE8361; | |
} | |
.outerwrapper svg .selected { | |
fill: #E85338; | |
} |