Skip to content

Instantly share code, notes, and snippets.

@baronwatts
Last active July 28, 2017 15:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baronwatts/2a50ae537d7c46670aa5eb30254ef751 to your computer and use it in GitHub Desktop.
Save baronwatts/2a50ae537d7c46670aa5eb30254ef751 to your computer and use it in GitHub Desktop.
ScrollyTelling Example
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/noframework.waypoints.js"></script>
<style>
@import url('https://fonts.googleapis.com/css?family=Open+Sans:300,600');
*{
margin:0;
padding:0;
}
html,
body{
height: 100%;
padding: 0;
scroll-behavior: smooth;
background: #f7f5f2;
color: #666;
font-family: 'Open Sans', sans-serif;
font-weight: 300;
}
h2{
line-height: 1.25;
padding-top: 45px;
font-weight: 300;
}
svg{
padding: 20px;
}
text{
font-size: 10px;
}
strong{
font-weight: 600;
}
#graphic {
max-width: 1440px;
width: 100%;
position: relative;
height: 100%;
position: relative;
margin:auto;
}
.container {
height: 100%;
max-width: 440px;
width: 100%;
margin: 0;
padding: 0;
position: absolute;
height: 100%;
line-height: 1.5;
left: 500px;
}
.container div {
height: 100%;
display: block;
padding: 0 45px;
}
.fixed {
position: fixed;
max-width: 500px;
height: 500px;
top: 50px;
}
</style>
</head>
<body>
<div id="graphic">
<div class="container">
<div id="div1">
<h2>On <strong>July 27, 2017</strong> there were <strong>20</strong> people attending the Data Visualization meetup.</h2>
</div>
<div id="div2">
<h2>Out of those <strong>20</strong> there were <strong>12</strong> people who attended.</h2>
<p></p>
</div>
<div id="div4">
<h2><strong>5</strong> out of <strong>12</strong> people had iphones. The other <strong>7</strong> had android devices</h2>
</div>
<div id="div6">
<h2>Out of those <strong>12</strong> attendees only <strong>3</strong> people were San Diego natives. <br><br>The age group for the attendees ranged between 25 and 65.</h2>
</div>
</div>
<!-- svg -->
<div class="fixed"><svg id="viz" width="100%" height="100%"></svg></div>
</div><!-- /graphic -->
<script>
//svg
let svg = d3.select("svg");
//svg width and height
svg.attr('width',500)
.attr('height',500)
//set up grid spacing
let spacing = 40;
let rows = 10;
let column = 10;
let randnum = (min,max) => Math.round( Math.random() * (max-min) + min );
//Create an array of objects
let our_data = d3.range(20).map(i =>
({ 'device': i < 5 ? 'ios' : 'android',
'city': i < 3 ? 'San Diegan' : 'Out of towners',
'age': randnum(25, 65)
}));
//create group and join our data to that group
let group = svg.selectAll('g')
.data(our_data)
.enter()
.append("g")
//create rectangles
let rects = group.append("rect")
//city data
d3.selectAll('g')
.append("text")
.text( (d) => d["city"])
.attr("fill", "gray")
.attr("class", "city")
.attr("dx", -500)
//age data
d3.selectAll('g')
.append("text")
.text( (d) => d["age"] )
.attr("fill", "#fff")
.attr("class", "age")
.attr("dx", -500)
// square grid
let grid = () =>{
rects
.transition()
.delay((d, i) => 10 * i)
.duration(600)
.ease("elastic")
.attr("width", 20)
.attr("height", 20)
.attr("rx", 5)
.attr("ry", 5)
.attr("x", (d, i) => i % column * spacing)
.attr("y", (d, i) => Math.floor(i / 10) % rows * spacing)
.attr("fill", (d, i) => (i < 40 ? "#394147" : "#99c125"))
.attr("opacity", "1")
}
//circle grid
let grid2 = () =>{
rects
.transition()
.delay((d, i) => 10 * i)
.duration(600)
.ease("elastic")
.attr("width", 20)
.attr("height", 20)
.attr("rx", "50%")
.attr("ry", "50%")
.attr("x", (d, i) => i % column * spacing)
.attr("y", (d, i) => Math.floor(i / 10) % rows * spacing)
.attr("fill", (d, i) => (i < 8 ? "none" : "#99c125"))
}
//divide
let divide = () =>{
rects
.transition()
.delay((d, i) => 10 * i)
.duration(600)
.ease("elastic")
.attr("width", 10)
.attr("height", 10)
.attr("rx", 0)
.attr("ry", 0)
.attr("x", (d, i) => d['device'] == "ios" ? randnum(100, 150) : randnum(300, 350))
.attr("y", (d, i) => i * 20)
.attr("fill", (d, i) => d['device'] == "ios" ? "#394147": "#99c125")
.attr("opacity", (d,i)=> i < 12 ? 1 : 0 )//only show 12 people
//age
d3.selectAll('text.age')
.transition()
.delay( (d,i) => 40*i )
.duration(900)
.ease('elastic')
.attr("dx", -500)
//city
d3.selectAll('text.city')
.transition()
.delay( (d,i) => 40*i )
.duration(900)
.ease('elastic')
.attr("dx", -500)
}
//bar cart
let barChart = () => {
rects
.attr("rx", 0 )
.attr("ry", 0 )
.transition()
.delay( (d,i) => 20*i )
.duration(900)
.ease('elastic')//linear, quad, cubic, sin, exp, circle, elastic, back, bounce
.attr("x", (d,i) => 150 )
.attr("y", (d,i) => i * 17 )
.attr("width", (d,i) => d["age"])
.attr("height", (d,i) => 15)
.attr("fill", (d, i) => (i < 3 ? "#99c125" : "#394147"))
.attr("opacity", 1)
.attr("transform", "translate(0,0) rotate(0)")
.attr("opacity", (d,i)=> i < 12 ? 1 : 0 )//only show 12 people
//age text
d3.selectAll('text.age')
.transition()
.delay( (d,i) => 20*i )
.duration(900)
.ease('elastic')
//align text right
.attr("text-anchor", "start")
.attr("dx", 160)
.attr("dy", (d,i)=> (i * 17) + 12)
.attr("opacity", (d,i)=> i < 12 ? 1 : 0 )//nly show 12 people
//city text
d3.selectAll('text.city')
.transition()
.delay( (d,i) => 20*i )
.duration(900)
.ease('elastic')
//align text left
.attr("text-anchor", "end")
.attr("dx", 140)
.attr("dy", (d,i)=> (i * 17) + 12)
.attr("opacity", (d,i)=> i < 12 ? 1 : 0 )//only show 12 people
}
//waypoints scroll constructor
function scroll(n, offset, func1, func2){
return new Waypoint({
element: document.getElementById(n),
handler: function(direction) {
direction == 'down' ? func1() : func2();
},
//start 75% from the top of the div
offset: offset
});
};
//triger these functions on page scroll
new scroll('div2', '75%', grid2, grid);
new scroll('div4', '75%', divide, grid);
new scroll('div6', '75%', barChart, divide);
//start grid on page load
grid();
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment