Edited for my D3.Unconf 2016 badge :D
Code is horrendously ugly and hacky because it was made in a rush, please don't judge.
Built with blockbuilder.org
forked from sxywu's block: DS July: Code 1
forked from sxywu's block: DS July: Code 2
forked from sxywu's block: DS July: Code 3
forked from sxywu's block: DS July: Code 4
forked from sxywu's block: DS July: Code 5
forked from sxywu's block: DS July: Code 6
forked from sxywu's block: DS July: Code 7
xxxxxxxxxx
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js'></script>
<link href='https://fonts.googleapis.com/css?family=Libre+Baskerville:400,700' rel='stylesheet' type='text/css'>
<style>
body {
font-family: "Libre Baskerville";
color: #444;
overflow: hidden;
width: 1050px;
height: 1500px;
margin: 0;
}
svg {
position: absolute;
width: 1050px;
height: 1500px;
}
/* blend options taken from visual cinnamon tutorial: https://www.visualcinnamon.com/2016/05/beautiful-color-blending-svg-d3.html */
/*Set isolate on the group element*/
.flower {
isolation: isolate;
cursor: pointer;
}
/*Set blend mode on SVG element: e.g. screen, multiply*/
.flower circle, .legend circle { mix-blend-mode: multiply; }
</style>
</head>
<body>
<svg></svg>
<script>
var strokeColor = '#444';
var flowerSize = 150;
var padding = 20;
var width = 1050;
var height = 1500;
var legend = d3.select('.header svg');
var svg = d3.select('svg')
.append('g').attr('transform', 'translate(' + [width / 2, width / 2] + ')');
var petalPaths = [[
'M0 0',
"C50 50 50 100 0 100",
'L0 100',
'L0 100',
"C-50 100 -50 50 0 0"
],
[
'M0 0',
'C50 40 50 70 20 100',
'L0 85',
'L-20 100',
'C-50 70 -50 40 0 0'
]];
var leaf = [
'M0 15',
'C15 40 15 60 0 75',
'C-15 60 -15 40 0 15'
];
var numPetalScale = d3.scaleQuantize()
.range(_.range(5, 15));
var flowerSizeScale = d3.scaleLinear()
.range([0, 4]);
var petalScale = d3.scaleOrdinal()
.domain(['G', 'PG-13'])
.range(_.range(4));
var petalColors = d3.scaleOrdinal()
.range(['#FFC8F0', '#CBF2BD', '#AFE9FF','#FFB09E','#FFF2B4']);
// blur effect taken from visualcinnamon:
// https://www.visualcinnamon.com/2016/05/real-life-motion-effects-d3-visualization.html
var defs = svg.append("defs");
defs.append("filter")
.attr("id", "motionFilter") //Give it a unique ID
.attr("width", "300%") //Increase the width of the filter region to remove blur "boundary"
.attr("x", "-100%") //Make sure the center of the "width" lies in the middle of the element
.append("feGaussianBlur") //Append a filter technique
.attr("in", "SourceGraphic") //Perform the blur on the applied element
.attr("stdDeviation", "8 8"); //Do a blur of 8 standard deviations in the horizontal and vertical direction
/*****************************************************
** get movie data
******************************************************/
d3.json('movies.json', function(movies) {
movies = _.chain(movies)
.map(function(movie) {
movie.year = parseInt(movie.Year);
movie.genres = movie.Genre.split(', ');
movie.rating = parseFloat(movie.imdbRating);
movie.votes = parseInt(movie.imdbVotes.replace(/\,/g, ''));
return movie;
}).sortBy(function(movie) {
return -movie.year
}).value();
// number of petals depending on number of rating votes
var minVotes = d3.min(movies, function(d) {return d.votes});
var maxVotes = d3.max(movies, function(d) {return d.votes});
numPetalScale.domain([minVotes, maxVotes]);
// overall flower size from rating
var minRating = d3.min(movies, function(d) {return d.rating});
var maxRating = d3.max(movies, function(d) {return d.rating});
flowerSizeScale.domain([minRating, maxRating]);
// get the top 4 genres by count
var topGenres = _.chain(movies)
.map('genres').flatten()
.countBy().toPairs()
.sortBy(1).map(0)
.takeRight(4)
.value();
topGenres.push('Other');
petalColors.domain(topGenres);
// get all the years
var allYears = _.chain(movies)
.map('year').uniq().value();
/*****************************************************
** draw first flower
******************************************************/
var movie1 = _.find(movies, function(m) {
return _.includes(m.Title, 'Harry Potter');
});
// draw flower for each movie
var flowers = svg.append('g')
.datum(movie1)
.classed('flower', true)
.attr('transform', function(d, i) {
var scale = flowerSizeScale(d.rating);
return 'scale(' + scale + ')';
});
// create the data for each flower's colors
flowers.selectAll('circle')
.data(function(d) {
return _.map(d.genres, function(genre, i) {
genre = _.includes(topGenres, genre) ? genre : 'Other';
return {
scale: flowerSizeScale(d.rating),
angle: (360/d.genres.length) * i,
fill: petalColors(genre)
}
});
}).enter().append('circle')
.attr('cy', -flowerSize / 4)
.attr('r', flowerSize / 2)
.attr('fill', function(d) {return d.fill})
.attr('transform', function(d) {
var x = flowerSize / 2 / d.scale;
var y = flowerSize / 2 / d.scale;
return 'translate(' + [x, y] +
')rotate(' + d.angle + ')';
}).style("filter", "url(#motionFilter)");
// draw the flower petals
flowers.selectAll('path.petal')
.data(function(d) {
var numPetals = numPetalScale(d.votes);
var path = petalPaths[petalScale(d.Rated)];
return _.times(numPetals, function(i) {
return {
scale: flowerSizeScale(d.rating),
angle: (360/numPetals) * i,
path: path
}
});
}).enter().append('path')
.classed('petal', true)
.attr('stroke', strokeColor)
.attr('stroke-width', function(d) {
return 5 / d.scale;
}).attr('fill', 'none')
.attr('d', function(d) {return d.path.join(' ')})
.attr('transform', function(d) {
var cx = flowerSize / 2 / d.scale;
var cy = flowerSize / 2 / d.scale;
return 'translate(' + [cx, cy] +
')rotate(' + [d.angle] + ')';
});
// draw the leaves
flowers.selectAll('path.leaf')
.data(function(d) {
var leaves = [];
if (d.Seen) {
leaves.push({
scale: flowerSizeScale(d.rating),
angle: -120
});
}
if (d.SeenOnRelease) {
leaves.push({
scale: flowerSizeScale(d.rating),
angle: 120
});
}
return leaves;
}).enter().append('path')
.classed('leaf', true)
.attr('stroke', '#555')
.attr('stroke-width', function(d) {
return 5 / d.scale;
}).attr('fill', '#4AB56D')
.attr('d', leaf.join(' '))
.attr('opacity', 1)
.attr('transform', function(d) {
var cx = flowerSize / 2 / d.scale;
var cy = flowerSize / 2 / d.scale + flowerSize;
return 'translate(' + [cx, cy] +
')rotate(' + [d.angle] + ')';
});
// calculate center
var flowerWidth = flowers.node().getBoundingClientRect();
var flowerHeight = flowerWidth.height;
flowerWidth = flowerWidth.width;
flowers.attr('transform', function(d, i) {
var scale = flowerSizeScale(d.rating);
var x = (width * .35) - (flowerWidth / 2);
var y = (width * .45) - (flowerHeight / 2);
return 'translate(' + [x, y] + ')scale(' + scale + ')';
})
/*****************************************************
** draw first flower
******************************************************/
var movie2 = _.find(movies, function(m) {
return _.includes(m.Title, 'Toy Story');
});
var delay = 0;
var duration = 10000;
flowers.datum(movie2);
flowers.selectAll('circle').data(function(d) {
return _.map(d.genres, function(genre, i) {
genre = _.includes(topGenres, genre) ? genre : 'Other';
return {
scale: flowerSizeScale(d.rating),
angle: (360/d.genres.length) * i,
fill: petalColors(genre)
}
});
}).transition().delay(delay).duration(duration)
.attr('fill', function(d) {return d.fill});
flowers.selectAll('path.petal')
.data(function(d) {
var numPetals = numPetalScale(d.votes);
var path = petalPaths[petalScale(d.Rated)];
return _.times(numPetals, function(i) {
return {
scale: flowerSizeScale(d.rating),
angle: (360/numPetals) * i,
path: path
}
});
}).transition().delay(delay).duration(duration)
.attr('d', function(d) {return d.path.join(' ')});
flowers.selectAll('path.leaf')
.data(function(d) {
var leaves = [];
if (d.Seen) {
leaves.push({
scale: flowerSizeScale(d.rating),
angle: -120
});
}
if (d.SeenOnRelease) {
leaves.push({
scale: flowerSizeScale(d.rating),
angle: 120
});
}
return leaves;
}).exit().transition().delay(delay).duration(duration)
.attr('opacity', 0).remove();
// calculate center
var flowerWidth = flowers.node().getBoundingClientRect();
var flowerHeight = flowerWidth.height;
flowerWidth = flowerWidth.width;
flowers.transition().delay(delay).duration(duration)
.attr('transform', function(d, i) {
var scale = flowerSizeScale(d.rating);
var x = (width * .35) - (flowerWidth / 2);
var y = (width * .45) - (flowerHeight / 2);
return 'translate(' + [x, y] + ')scale(' + scale + ')';
});
});
</script>
</body>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js