13 KiB
13 KiB
id | title | challengeType | dashedName |
---|---|---|---|
5d8a4cfbe6b6180ed9a1ca6c | Part 140 | 0 | part-140 |
--description--
There's a problem, each time you hover a label it adds all the elements to the container again. If you empty the container at the top of the function, it will redraw them where they need to be.
Go back to the top of the function and use d3.select
to select the .dashboard
element and chain the html
function to it with an empty string as it parameter. Empty means no spaces.
--hints--
test-text
const script = $('.dashboard').siblings('script')[1].innerHTML;
assert(/d3\.select\(('|"|`)\.dashboard\1\)\.html\(('|"|`)\2\)/g.test(script));
--seed--
--before-user-code--
<!DOCTYPE html>
<html>
<head>
<title>D3 Dashboard</title>
<style>
body {
background-color: #ccc;
padding: 100px 10px;
}
.dashboard {
width: 980px;
height: 500px;
background-color: white;
box-shadow: 5px 5px 5px 5px #888;
margin: auto;
display: flex;
align-items: center;
}
</style>
</head>
<body>
<div class="dashboard"></div>
</body>
</html>
--seed-contents--
<script>
const data = [
{ year: 2012, followers: { twitter: 2594, tumblr: 401, instagram: 83 }},
{ year: 2013, followers: { twitter: 3049, tumblr: 440, instagram: 192 }},
{ year: 2014, followers: { twitter: 3511, tumblr: 415, instagram: 511 }},
{ year: 2015, followers: { twitter: 3619, tumblr: 492, instagram: 1014 }},
{ year: 2016, followers: { twitter: 4046, tumblr: 543, instagram: 2066 }},
{ year: 2017, followers: { twitter: 3991, tumblr: 701, instagram: 3032 }},
{ year: 2018, followers: { twitter: 3512, tumblr: 1522, instagram: 4512 }},
{ year: 2019, followers: { twitter: 3274, tumblr: 1989, instagram: 4715 }},
{ year: 2020, followers: { twitter: 2845, tumblr: 2040, instagram: 4801 }}
];
</script>
<script>
function drawDashboard(year) {
const index = data.findIndex(d => d.year === year);
const svgMargin = 70,
svgWidth = 700,
svgHeight = 500,
twitterColor = '#7cd9d1',
tumblrColor = '#f6dd71',
instagramColor = '#fd9b98';
const lineGraph = d3.select('.dashboard')
.append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
const yScale = d3.scaleLinear()
.domain([0, 5000])
.range([svgHeight - svgMargin, svgMargin]);
const xScale = d3.scaleLinear()
.domain([2012, 2020])
.range([svgMargin, svgWidth - svgMargin]);
const yAxis = d3.axisLeft(yScale)
.ticks(6, '~s');
const xAxis = d3.axisBottom(xScale)
.tickFormat(d3.format(''))
.tickPadding(10);
lineGraph.append('g')
.call(yAxis)
.attr('transform', `translate(${svgMargin}, 0)`)
.style('font', '10px verdana');
lineGraph.append('g')
.call(xAxis)
.attr('transform', `translate(0, ${svgHeight - svgMargin})`)
.selectAll('text')
.style('transform', 'translate(-12px, 0) rotate(-50deg)')
.style('text-anchor', 'end')
.style('cursor', 'pointer')
.style('font', '10px verdana')
.on('mouseover', d => drawDashboard(d));
const twitterLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.twitter));
lineGraph.append('path')
.attr('d', twitterLine(data))
.attr('stroke', twitterColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
const tumblrLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.tumblr));
lineGraph.append('path')
.attr('d', tumblrLine(data))
.attr('stroke', tumblrColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
const instagramLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.instagram));
lineGraph.append('path')
.attr('d', instagramLine(data))
.attr('stroke', instagramColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
lineGraph.selectAll('twitter-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.twitter))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', twitterColor)
.style('cursor', 'pointer')
lineGraph.selectAll('tumblr-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.tumblr))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', tumblrColor)
.style('cursor', 'pointer')
lineGraph.selectAll('instagram-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.instagram))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', instagramColor)
.style('cursor', 'pointer')
const rightDashboard = d3.select('.dashboard')
.append('div');
const pieGraph = rightDashboard.append('svg')
.attr('width', 200)
.attr('height', 200)
.style('position', 'relative')
.style('left', '20px');
const pieArc = d3.arc()
.outerRadius(100)
.innerRadius(0);
const pieColors = d3.scaleOrdinal()
.domain(data[index].followers)
.range([twitterColor, tumblrColor, instagramColor]);
const pie = d3.pie()
.value(d => d.value);
const pieGraphData = pieGraph.selectAll('pieSlices')
.data(pie(d3.entries(data[index].followers)))
.enter()
.append('g')
.attr('transform', 'translate(100, 100)');
pieGraphData.append('path')
.attr('d', pieArc)
.attr('fill', d => pieColors(d.data.key))
.attr('stroke', 'white')
.attr('stroke-width', 2);
pieGraphData.append('text')
.text(d => {
const values = d3.values(data[index].followers);
const sum = d3.sum(values);
const percent = d.data.value/sum;
return `${ Math.round(percent*100) }%`;
})
.attr('transform', d => `translate(${pieArc.centroid(d)})`)
.style('text-anchor', 'middle')
.style('font', '10px verdana');
const legend = rightDashboard.append('table')
.attr('width', 200)
.attr('height', 120)
.style('font', '12px verdana')
.style('position', 'relative')
.style('top', '30px');
const legendTitle = legend.append('thead')
.append('tr')
.append('th')
.text('2020 followers')
.attr('colspan', 3)
.style('position', 'relative')
.style('left', '20px');
const legendRows = legend.append('tbody')
.selectAll('tr')
.data(d3.entries(data[index].followers))
.enter()
.append('tr');
legendRows.append('td')
.text(d => d.key)
.attr('align', 'right');
legendRows.append('td')
.attr('align', 'center')
.append('div')
.style('width', '16px')
.style('height', '16px')
.style('background-color', d => pieColors(d.key))
legendRows.append('td')
.text(d => d.value)
.attr('align', 'left');
}
drawDashboard(2020);
</script>
--solutions--
<script>
const data = [
{ year: 2012, followers: { twitter: 2594, tumblr: 401, instagram: 83 }},
{ year: 2013, followers: { twitter: 3049, tumblr: 440, instagram: 192 }},
{ year: 2014, followers: { twitter: 3511, tumblr: 415, instagram: 511 }},
{ year: 2015, followers: { twitter: 3619, tumblr: 492, instagram: 1014 }},
{ year: 2016, followers: { twitter: 4046, tumblr: 543, instagram: 2066 }},
{ year: 2017, followers: { twitter: 3991, tumblr: 701, instagram: 3032 }},
{ year: 2018, followers: { twitter: 3512, tumblr: 1522, instagram: 4512 }},
{ year: 2019, followers: { twitter: 3274, tumblr: 1989, instagram: 4715 }},
{ year: 2020, followers: { twitter: 2845, tumblr: 2040, instagram: 4801 }}
];
</script>
<script>
function drawDashboard(year) {
d3.select('.dashboard').html('');
const index = data.findIndex(d => d.year === year);
const svgMargin = 70,
svgWidth = 700,
svgHeight = 500,
twitterColor = '#7cd9d1',
tumblrColor = '#f6dd71',
instagramColor = '#fd9b98';
const lineGraph = d3.select('.dashboard')
.append('svg')
.attr('width', svgWidth)
.attr('height', svgHeight);
const yScale = d3.scaleLinear()
.domain([0, 5000])
.range([svgHeight - svgMargin, svgMargin]);
const xScale = d3.scaleLinear()
.domain([2012, 2020])
.range([svgMargin, svgWidth - svgMargin]);
const yAxis = d3.axisLeft(yScale)
.ticks(6, '~s');
const xAxis = d3.axisBottom(xScale)
.tickFormat(d3.format(''))
.tickPadding(10);
lineGraph.append('g')
.call(yAxis)
.attr('transform', `translate(${svgMargin}, 0)`)
.style('font', '10px verdana');
lineGraph.append('g')
.call(xAxis)
.attr('transform', `translate(0, ${svgHeight - svgMargin})`)
.selectAll('text')
.style('transform', 'translate(-12px, 0) rotate(-50deg)')
.style('text-anchor', 'end')
.style('cursor', 'pointer')
.style('font', '10px verdana')
.on('mouseover', d => drawDashboard(d));
const twitterLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.twitter));
lineGraph.append('path')
.attr('d', twitterLine(data))
.attr('stroke', twitterColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
const tumblrLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.tumblr));
lineGraph.append('path')
.attr('d', tumblrLine(data))
.attr('stroke', tumblrColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
const instagramLine = d3.line()
.x(d => xScale(d.year))
.y(d => yScale(d.followers.instagram));
lineGraph.append('path')
.attr('d', instagramLine(data))
.attr('stroke', instagramColor)
.attr('stroke-width', 3)
.attr('fill', 'transparent');
lineGraph.selectAll('twitter-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.twitter))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', twitterColor)
.style('cursor', 'pointer')
lineGraph.selectAll('tumblr-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.tumblr))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', tumblrColor)
.style('cursor', 'pointer')
lineGraph.selectAll('instagram-circles')
.data(data)
.enter()
.append('circle')
.attr('cx', d => xScale(d.year))
.attr('cy', d => yScale(d.followers.instagram))
.attr('r', 6)
.attr('fill', 'white')
.attr('stroke', instagramColor)
.style('cursor', 'pointer')
const rightDashboard = d3.select('.dashboard')
.append('div');
const pieGraph = rightDashboard.append('svg')
.attr('width', 200)
.attr('height', 200)
.style('position', 'relative')
.style('left', '20px');
const pieArc = d3.arc()
.outerRadius(100)
.innerRadius(0);
const pieColors = d3.scaleOrdinal()
.domain(data[index].followers)
.range([twitterColor, tumblrColor, instagramColor]);
const pie = d3.pie()
.value(d => d.value);
const pieGraphData = pieGraph.selectAll('pieSlices')
.data(pie(d3.entries(data[index].followers)))
.enter()
.append('g')
.attr('transform', 'translate(100, 100)');
pieGraphData.append('path')
.attr('d', pieArc)
.attr('fill', d => pieColors(d.data.key))
.attr('stroke', 'white')
.attr('stroke-width', 2);
pieGraphData.append('text')
.text(d => {
const values = d3.values(data[index].followers);
const sum = d3.sum(values);
const percent = d.data.value/sum;
return `${ Math.round(percent*100) }%`;
})
.attr('transform', d => `translate(${pieArc.centroid(d)})`)
.style('text-anchor', 'middle')
.style('font', '10px verdana');
const legend = rightDashboard.append('table')
.attr('width', 200)
.attr('height', 120)
.style('font', '12px verdana')
.style('position', 'relative')
.style('top', '30px');
const legendTitle = legend.append('thead')
.append('tr')
.append('th')
.text('2020 followers')
.attr('colspan', 3)
.style('position', 'relative')
.style('left', '20px');
const legendRows = legend.append('tbody')
.selectAll('tr')
.data(d3.entries(data[index].followers))
.enter()
.append('tr');
legendRows.append('td')
.text(d => d.key)
.attr('align', 'right');
legendRows.append('td')
.attr('align', 'center')
.append('div')
.style('width', '16px')
.style('height', '16px')
.style('background-color', d => pieColors(d.key))
legendRows.append('td')
.text(d => d.value)
.attr('align', 'left');
}
drawDashboard(2020);
</script>