Oliver Eyton-Williams ee1e8abd87
feat(curriculum): restore seed + solution to Chinese (#40683)
* feat(tools): add seed/solution restore script

* chore(curriculum): remove empty sections' markers

* chore(curriculum): add seed + solution to Chinese

* chore: remove old formatter

* fix: update getChallenges

parse translated challenges separately, without reference to the source

* chore(curriculum): add dashedName to English

* chore(curriculum): add dashedName to Chinese

* refactor: remove unused challenge property 'name'

* fix: relax dashedName requirement

* fix: stray tag

Remove stray `pre` tag from challenge file.

Signed-off-by: nhcarrigan <nhcarrigan@gmail.com>

Co-authored-by: nhcarrigan <nhcarrigan@gmail.com>
2021-01-12 19:31:00 -07:00

14 KiB

id, title, challengeType, dashedName
id title challengeType dashedName
5d8a4cfbe6b6180ed9a1ca71 Part 145 0 part-145

--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.

--hints--

test-text

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
);

--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) {
    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>

--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', 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>