* fix: remove isHidden key from tool template * fix: removed isHidden key from English challenges * fix: remove isHidden key from Chinese challenges
14 KiB
14 KiB
id, title, challengeType
id | title | challengeType |
---|---|---|
5d8a4cfbe6b6180ed9a1ca71 | Part 145 | 0 |
Description
Change the fill
of the tumblr-circles
and instagram-circles
to use a "d function" that returns their respective color variables when d.year
equals year
, leave it white
when they don't. This is similar to how you set the fill of the Twitter circles.
Then, all of the circles will get filled in for the currently displayed year.
Instructions
Tests
tests:
- text: test-text
testString: const circles = Object.values($('.dashboard svg circle')); assert(circles.filter(el => el.getAttribute && (el.getAttribute('fill') === '#7cd9d1' || el.getAttribute('fill') === '#f6dd71' || el.getAttribute('fill') === '#fd9b98')).length === 3);
Challenge Seed
<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', d => d === year ? 'bold 10px verdana' : '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', d => d.year === year ? twitterColor : 'white')
.attr('stroke', twitterColor)
.style('cursor', 'pointer')
.on('mouseover', d => drawDashboard(d.year));
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')
.on('mouseover', d => drawDashboard(d.year));
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')
.on('mouseover', d => drawDashboard(d.year));
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>
Before Test
<!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>
Solution
<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', d => d === year ? 'bold 10px verdana' : '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', d => d.year === year ? twitterColor : 'white')
.attr('stroke', twitterColor)
.style('cursor', 'pointer')
.on('mouseover', d => drawDashboard(d.year));
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', d => d.year === year ? tumblrColor : 'white')
.attr('stroke', tumblrColor)
.style('cursor', 'pointer')
.on('mouseover', d => drawDashboard(d.year));
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', d => d.year === year ? instagramColor : 'white')
.attr('stroke', instagramColor)
.style('cursor', 'pointer')
.on('mouseover', d => drawDashboard(d.year));
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>