Skip to content

Instantly share code, notes, and snippets.

@ckinmind
Last active May 31, 2018 07:33
Show Gist options
  • Save ckinmind/5e5dca19630176672971febc88eeb6fc to your computer and use it in GitHub Desktop.
Save ckinmind/5e5dca19630176672971febc88eeb6fc to your computer and use it in GitHub Desktop.
Pie——Animate Pie
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body {
overflow: hidden;
font-size: 16px;
}
.chart-wrapper {
width: 100%;
height: 100%;
background-color: #0d0d0d;
position: absolute;
}
path {
stroke: #0d0d0d;
/* stroke-width: 5px; */
cursor: pointer;
transition: fill 250ms;
}
path:hover {
/* stroke-width: 10px; */
fill: #fff;
}
text {
font-size: .8em;
text-transform: uppercase;
letter-spacing: .5px;
}
polyline {
fill: none;
stroke: #fff;
stroke-width: 2px;
stroke-dasharray: 5px;
}
button {
position: absolute;
top: 20px;
left: 20px;
text-transform: uppercase;
cursor: pointer;
padding: 5px 10px;
outline: none;
font-size: .6em;
background-color: transparent;
color: #fff;
border: 1px solid #fff;
letter-spacing: 1px;
transition: all 250ms;
}
button:hover {
background-color: #fff;
color: #0d0d0d;
box-shadow: 0 0 2px #fff;
}
button:active {
opacity: 0.5;
}
</style>
</head>
<body>
<div class="chart-wrapper"></div>
<button onclick='replay()'>Replay</button>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script>
const dataset = [1, 2, 3, 4, 6, 7, 8, 1, 1, 1]
// let colors = ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd'];
// let colors = ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a'];
const colors = ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2']
const width = document.querySelector('.chart-wrapper').offsetWidth
const height = document.querySelector('.chart-wrapper').offsetHeight
const minOfWH = Math.min(width, height) / 2
const initialAnimDelay = 300
const arcAnimDelay = 150
const arcAnimDur = 3000
const secDur = 1000
const secIndividualdelay = 150
let radius
// calculate minimum of width and height to set chart radius
if (minOfWH > 200) {
radius = 200
} else {
radius = minOfWH
}
// append svg
let svg = d3.select('.chart-wrapper').append('svg')
.attr({
'width': width,
'height': height,
'class': 'pieChart'
})
.append('g')
svg.attr({
'transform': `translate(${width / 2}, ${height / 2})`
});
// for drawing slices
let arc = d3.svg.arc()
.outerRadius(radius * 0.6)
.innerRadius(radius * 0.45)
// for labels and polylines
let outerArc = d3.svg.arc()
.innerRadius(radius * 0.85)
.outerRadius(radius * 0.85)
// d3 color generator
// let c10 = d3.scale.category10();
let pie = d3.layout.pie()
.value(d => d)
let draw = function() {
svg.append("g").attr("class", "lines")
svg.append("g").attr("class", "slices")
svg.append("g").attr("class", "labels")
// define slice
let slice = svg.select('.slices')
.datum(dataset)
.selectAll('path')
.data(pie)
slice
.enter().append('path')
.attr({
'fill': (d, i) => colors[i],
'd': arc,
'stroke-width': '25px',
'transform': (d, i) => 'rotate(-180, 0, 0)'
})
.style('opacity', 0)
.transition()
.delay((d, i) => (i * arcAnimDelay) + initialAnimDelay)
.duration(arcAnimDur)
.ease('elastic')
.style('opacity', 1)
.attr('transform', 'rotate(0,0,0)')
slice.transition()
.delay((d, i) => arcAnimDur + (i * secIndividualdelay))
.duration(secDur)
.attr('stroke-width', '5px')
let midAngle = d => d.startAngle + (d.endAngle - d.startAngle) / 2
let text = svg.select(".labels").selectAll("text")
.data(pie(dataset))
text.enter()
.append('text')
.attr('dy', '0.35em')
.style("opacity", 0)
.style('fill', (d, i) => colors[i])
.text((d, i) => colors[i])
.attr('transform', d => {
// calculate outerArc centroid for 'this' slice
let pos = outerArc.centroid(d)
// define left and right alignment of text labels
pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1)
return `translate(${pos})`
})
.style('text-anchor', d => midAngle(d) < Math.PI ? "start" : "end")
.transition()
.delay((d, i) => arcAnimDur + (i * secIndividualdelay))
.duration(secDur)
.style('opacity', 1)
let polyline = svg.select(".lines").selectAll("polyline")
.data(pie(dataset))
polyline.enter()
.append("polyline")
.style("opacity", 0.5)
.attr('points', d => {
let pos = outerArc.centroid(d)
pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1)
return [arc.centroid(d), arc.centroid(d), arc.centroid(d)]
})
.transition()
.duration(secDur)
.delay((d, i) => arcAnimDur + (i * secIndividualdelay))
.attr('points', d => {
let pos = outerArc.centroid(d)
pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1)
return [arc.centroid(d), outerArc.centroid(d), pos]
})
}
draw()
let button = document.querySelector('button');
let replay = () => {
d3.selectAll('.slices').transition().ease('back').duration(500).delay(0).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
d3.selectAll('.lines').transition().ease('back').duration(500).delay(100).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
d3.selectAll('.labels').transition().ease('back').duration(500).delay(200).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
setTimeout(draw, 800)
}
</script>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body {
overflow: hidden;
font-size: 16px;
}
.chart-wrapper {
width: 100%;
height: 100%;
background-color: #0d0d0d;
position: absolute;
}
path {
stroke: #0d0d0d;
/* stroke-width: 5px; */
cursor: pointer;
transition: fill 250ms;
}
path:hover {
/* stroke-width: 10px; */
fill: #fff;
}
text {
font-size: .8em;
text-transform: uppercase;
letter-spacing: .5px;
}
polyline {
fill: none;
stroke: #fff;
stroke-width: 2px;
stroke-dasharray: 5px;
}
button {
position: absolute;
top: 20px;
left: 20px;
text-transform: uppercase;
cursor: pointer;
padding: 5px 10px;
outline: none;
font-size: .6em;
background-color: transparent;
color: #fff;
border: 1px solid #fff;
letter-spacing: 1px;
transition: all 250ms;
}
button:hover {
background-color: #fff;
color: #0d0d0d;
box-shadow: 0 0 2px #fff;
}
button:active {
opacity: 0.5;
}
</style>
</head>
<body>
<div class="chart-wrapper"></div>
<button onclick='replay()'>Replay</button>
<script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<script>
// const dataset = [10, 2, 3, 4]
const dataset = [
{name: 'hehe', value: 10},
{name: 'haha', value: 2},
{name: 'huhu', value: 3},
{name: 'hihi', value: 4},
]
// let colors = ['#8dd3c7', '#ffffb3', '#bebada', '#fb8072', '#80b1d3', '#fdb462', '#b3de69', '#fccde5', '#d9d9d9', '#bc80bd'];
// let colors = ['#67001f', '#b2182b', '#d6604d', '#f4a582', '#fddbc7', '#e0e0e0', '#bababa', '#878787', '#4d4d4d', '#1a1a1a'];
const colors = ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2']
const width = document.querySelector('.chart-wrapper').offsetWidth
const height = document.querySelector('.chart-wrapper').offsetHeight
const radius = 400
// append svg
let svg = d3.select('.chart-wrapper').append('svg')
.attr('width', width)
.attr('height', height)
.attr('class', 'pieChart')
.append('g')
svg.attr('transform', `translate(${width / 2}, ${height / 2})`)
// for drawing slices
let arc = d3.arc()
.outerRadius(radius * 0.7)
.innerRadius(radius * 0.55)
// .startAngle(0)
// for labels and polylines
let outerArc = d3.arc()
.innerRadius(radius * 0.85)
.outerRadius(radius * 0.85)
// d3 color generator
// let c10 = d3.scale.category10();
let pie = d3.pie()
.value(d => d.value)
// .startAngle(-0.5 * Math.PI)
// .endAngle(2* Math.PI);
let draw = function() {
svg.append("g").attr("class", "lines")
svg.append("g").attr("class", "slices")
svg.append("g").attr("class", "labels")
// define slice
let slice = svg.select('.slices')
// .datum(dataset)
.selectAll('path')
.data(pie(dataset))
console.log(pie(dataset))
slice
.enter()
.append('path')
.attr('fill', (d, i) => {
// console.log(d)
return colors[i]
})
.attr('d', arc)
.attr('stroke-width', 5)
.attr('transform', (d, i) => 'rotate(0, 0, 0)')
.style('opacity', 0)
.transition()
.delay((d, i) => (i * 150) + 300)
.duration(3000)
.ease(d3.easeElastic)
.style('opacity', 1)
.attr('transform', 'rotate(0,0,0)')
// slice.transition()
// .delay((d, i) => 3000 + (i * 150))
// .duration(1000)
// .attr('stroke-width', 10)
let midAngle = d => d.startAngle + (d.endAngle - d.startAngle) * 0.45
let text = svg.select(".labels").selectAll("text")
.data(pie(dataset))
text.enter()
.append('text')
.attr('dy', '0.35em')
.style("opacity", 0)
.style('fill', (d, i) => colors[i])
.text((d, i) => colors[i])
.attr('transform', d => {
// calculate outerArc centroid for 'this' slice
let pos = outerArc.centroid(d)
// define left and right alignment of text labels
pos[0] = radius * (midAngle(d) < Math.PI ? 1 : -1)
return `translate(${pos})`
})
.style('text-anchor', d => midAngle(d) < Math.PI ? "start" : "end")
.transition()
.delay((d, i) => 3000 + (i * 150))
.duration(1000)
.style('opacity', 1)
let polyline = svg.select(".lines").selectAll("polyline")
.data(pie(dataset))
polyline.enter()
.append("polyline")
.style("opacity", 0.5)
.attr('points', d => {
let pos = outerArc.centroid(d)
pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1)
return [arc.centroid(d), arc.centroid(d), arc.centroid(d)]
})
.transition()
.duration(1000)
.delay((d, i) => 3000 + (i * 150))
.attr('points', d => {
let pos = outerArc.centroid(d)
pos[0] = radius * 0.95 * (midAngle(d) < Math.PI ? 1 : -1)
return [arc.centroid(d), outerArc.centroid(d), pos]
})
}
draw()
let button = document.querySelector('button');
let replay = () => {
d3.selectAll('.slices').transition().ease(d3.easeBack).duration(500).delay(0).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
d3.selectAll('.lines').transition().ease(d3.easeBack).duration(500).delay(100).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
d3.selectAll('.labels').transition().ease(d3.easeBack).duration(500).delay(200).style('opacity', 0).attr('transform', 'translate(0, 250)').remove()
setTimeout(draw, 800)
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment