mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-30 03:03:06 -05:00
Feat: add d3 dashboard project to next curriculum (#38028)
* feat: add d3 dashboard project to next curriculum
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Introduction to the D3 Dashboard Project Challenges
|
||||
block: D3 Dashboard Project
|
||||
superBlock: Data Visualization
|
||||
---
|
||||
## Introduction to the D3 Dashboard Project Challenges
|
||||
|
||||
<dfn>D3 Dashboard Project</dfn> Placeholder Introduction.
|
||||
@@ -136,5 +136,6 @@ exports.helpCategory = {
|
||||
'basic-javascript-rpg-game': 'JavaScript',
|
||||
'functional-programming-spreadsheet': 'JavaScript',
|
||||
'intermediate-javascript-calorie-counter':
|
||||
'Intermediate JavaScript Calorie Counter'
|
||||
'Intermediate JavaScript Calorie Counter',
|
||||
'd3-dashboard-project': 'JavaScript'
|
||||
};
|
||||
|
||||
602
curriculum/challenges/_meta/d3-dashboard/meta.json
Normal file
602
curriculum/challenges/_meta/d3-dashboard/meta.json
Normal file
@@ -0,0 +1,602 @@
|
||||
{
|
||||
"name": "D3 Dashboard Project",
|
||||
"dashedName": "d3-dashboard",
|
||||
"order": 4,
|
||||
"time": "5 hours",
|
||||
"template": "",
|
||||
"required": [
|
||||
{
|
||||
"src": "https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.2/d3.min.js"
|
||||
}
|
||||
],
|
||||
"superBlock": "data-visualization",
|
||||
"superOrder": 4,
|
||||
"challengeOrder": [
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9de",
|
||||
"Part 1"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9df",
|
||||
"Part 2"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e0",
|
||||
"Part 3"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e1",
|
||||
"Part 4"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e2",
|
||||
"Part 5"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e3",
|
||||
"Part 6"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e4",
|
||||
"Part 7"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e5",
|
||||
"Part 8"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e6",
|
||||
"Part 9"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e7",
|
||||
"Part 10"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e8",
|
||||
"Part 11"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9e9",
|
||||
"Part 12"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ea",
|
||||
"Part 13"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9eb",
|
||||
"Part 14"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ec",
|
||||
"Part 15"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ed",
|
||||
"Part 16"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ee",
|
||||
"Part 17"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ef",
|
||||
"Part 18"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f0",
|
||||
"Part 19"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f1",
|
||||
"Part 20"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f2",
|
||||
"Part 21"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f3",
|
||||
"Part 22"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f4",
|
||||
"Part 23"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f5",
|
||||
"Part 24"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f6",
|
||||
"Part 25"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f7",
|
||||
"Part 26"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f8",
|
||||
"Part 27"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9f9",
|
||||
"Part 28"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9fa",
|
||||
"Part 29"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9fb",
|
||||
"Part 30"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9fc",
|
||||
"Part 31"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9fd",
|
||||
"Part 32"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9fe",
|
||||
"Part 33"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1c9ff",
|
||||
"Part 34"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca00",
|
||||
"Part 35"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca01",
|
||||
"Part 36"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca02",
|
||||
"Part 37"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca03",
|
||||
"Part 38"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca04",
|
||||
"Part 39"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca05",
|
||||
"Part 40"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca06",
|
||||
"Part 41"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca07",
|
||||
"Part 42"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca08",
|
||||
"Part 43"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca09",
|
||||
"Part 44"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0a",
|
||||
"Part 45"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0b",
|
||||
"Part 46"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0c",
|
||||
"Part 47"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0d",
|
||||
"Part 48"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0e",
|
||||
"Part 49"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca0f",
|
||||
"Part 50"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca10",
|
||||
"Part 51"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca11",
|
||||
"Part 52"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca12",
|
||||
"Part 53"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca13",
|
||||
"Part 54"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca14",
|
||||
"Part 55"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca15",
|
||||
"Part 56"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca16",
|
||||
"Part 57"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca17",
|
||||
"Part 58"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca18",
|
||||
"Part 59"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca19",
|
||||
"Part 60"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1a",
|
||||
"Part 61"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1b",
|
||||
"Part 62"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1c",
|
||||
"Part 63"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1d",
|
||||
"Part 64"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1e",
|
||||
"Part 65"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca1f",
|
||||
"Part 66"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca20",
|
||||
"Part 67"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca21",
|
||||
"Part 68"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca22",
|
||||
"Part 69"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca23",
|
||||
"Part 70"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca24",
|
||||
"Part 71"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca25",
|
||||
"Part 72"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca26",
|
||||
"Part 73"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca27",
|
||||
"Part 74"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca28",
|
||||
"Part 75"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca29",
|
||||
"Part 76"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2a",
|
||||
"Part 77"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2b",
|
||||
"Part 78"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2c",
|
||||
"Part 79"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2d",
|
||||
"Part 80"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2e",
|
||||
"Part 81"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca2f",
|
||||
"Part 82"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca30",
|
||||
"Part 83"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca31",
|
||||
"Part 84"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca32",
|
||||
"Part 85"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca33",
|
||||
"Part 86"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca34",
|
||||
"Part 87"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca35",
|
||||
"Part 88"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca36",
|
||||
"Part 89"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca37",
|
||||
"Part 90"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca38",
|
||||
"Part 91"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca39",
|
||||
"Part 92"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3a",
|
||||
"Part 93"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3b",
|
||||
"Part 94"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3c",
|
||||
"Part 95"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3d",
|
||||
"Part 96"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3e",
|
||||
"Part 97"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca3f",
|
||||
"Part 98"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca40",
|
||||
"Part 99"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca41",
|
||||
"Part 100"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca42",
|
||||
"Part 101"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca43",
|
||||
"Part 102"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca44",
|
||||
"Part 103"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca47",
|
||||
"Part 104"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca48",
|
||||
"Part 105"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca49",
|
||||
"Part 106"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4a",
|
||||
"Part 107"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4b",
|
||||
"Part 108"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4c",
|
||||
"Part 109"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4d",
|
||||
"Part 110"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4e",
|
||||
"Part 111"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca4f",
|
||||
"Part 112"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca50",
|
||||
"Part 113"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca51",
|
||||
"Part 114"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca52",
|
||||
"Part 115"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca53",
|
||||
"Part 116"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca54",
|
||||
"Part 117"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca55",
|
||||
"Part 118"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca56",
|
||||
"Part 119"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca57",
|
||||
"Part 120"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca58",
|
||||
"Part 121"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca59",
|
||||
"Part 122"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5a",
|
||||
"Part 123"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5b",
|
||||
"Part 124"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5c",
|
||||
"Part 125"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5d",
|
||||
"Part 126"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5e",
|
||||
"Part 127"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca5f",
|
||||
"Part 128"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca60",
|
||||
"Part 129"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca61",
|
||||
"Part 130"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca62",
|
||||
"Part 131"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca63",
|
||||
"Part 132"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca64",
|
||||
"Part 133"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca65",
|
||||
"Part 134"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca66",
|
||||
"Part 135"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca67",
|
||||
"Part 136"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca68",
|
||||
"Part 137"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6a",
|
||||
"Part 138"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6b",
|
||||
"Part 139"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6c",
|
||||
"Part 140"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6d",
|
||||
"Part 141"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6e",
|
||||
"Part 142"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca6f",
|
||||
"Part 143"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca70",
|
||||
"Part 144"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca71",
|
||||
"Part 145"
|
||||
],
|
||||
[
|
||||
"5d8a4cfbe6b6180ed9a1ca72",
|
||||
"Part 146"
|
||||
]
|
||||
],
|
||||
"helpRoom": "Help",
|
||||
"fileName": "04-data-visualization/d3-dashboard.json"
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9de
|
||||
title: Part 1
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Welcome to the dashboard project! You will be using the JavaScript data visualization library, D3, to build a visualization of your social media followers. It will consist of a line graph, a pie chart, and a legend.
|
||||
|
||||
First, you need to create the HTML file. Start by adding the `<!DOCTYPE html>` declaration at the top of the file to tell the browser what type of document it's reading.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/<!DOCTYPE\s+html\s*>/gi.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,95 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e7
|
||||
title: Part 10
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Give the container some space by adding a `padding` of `100px 10px` to the `body` element.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const body = code.match(/body\s*{[\s\S]+?[^}]}/g)[0]; assert(/padding\s*:\s*100px\s*10px\s*(;|})/g.test(body));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<style>
|
||||
body {
|
||||
background-color: #ccc;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
width: 980px;
|
||||
height: 500px;
|
||||
background-color: white;
|
||||
box-shadow: 5px 5px 5px 5px #888;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,392 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca41
|
||||
title: Part 100
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The pie graph is being drawn at the `0, 0` coordinates of the SVG. Back on your `pieGraphData` variable, add an attribute that changes the `transform` to `translate(100, 100)`.
|
||||
|
||||
Since the pie chart has a radius of 100, and the SVG is 200 by 200, this will move it so it is centered.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const transform = $('.dashboard div svg g')[0].getAttribute('transform'); assert(/translate\s*\(\s*100\s*,\s*100\s*\)/g.test(transform));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('g')
|
||||
|
||||
|
||||
pieGraphData.append('path')
|
||||
.attr('d', pieArc)
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
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);
|
||||
|
||||
const pieArc = d3
|
||||
.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3
|
||||
.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie().value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph
|
||||
.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('transform', 'translate(100, 100)');
|
||||
|
||||
pieGraphData.append('path')
|
||||
.attr('d', pieArc)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,397 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca42
|
||||
title: Part 101
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<section id='description'>
|
||||
|
||||
Back at the bottom, where you draw the chart. Use the `attr` function to set the `fill` to a "d function". In the "d function", use your `pieColors` scale to get the color value for the platform(`d.data.key`). So when each platform is passed to your scale, is will get the appropriate color to use as the fill from the scales range.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const pathsArr = $('.dashboard div svg g path'); assert(pathsArr[0].getAttribute('fill') === '#7cd9d1' && pathsArr[1].getAttribute('fill') === '#f6dd71' && pathsArr[2].getAttribute('fill') === '#fd9b98');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
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);
|
||||
|
||||
const pieArc = d3
|
||||
.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3
|
||||
.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie().value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph
|
||||
.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('transform', 'translate(100, 100)');
|
||||
|
||||
pieGraphData.append('path')
|
||||
.attr('d', pieArc)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
### Before Test
|
||||
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
## Solution
|
||||
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('transform', 'translate(100, 100)');
|
||||
|
||||
pieGraphData.append('path')
|
||||
.attr('d', pieArc)
|
||||
.attr('fill', d => pieColors(d.data.key))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,381 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca43
|
||||
title: Part 102
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Next, set the `stroke` to `white` and the `stroke-width` to `2`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const pathsArr = $('.dashboard div svg g path'); assert(pathsArr[0].getAttribute('stroke') === 'white' && pathsArr[0].getAttribute('stroke-width') == 2);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('g')
|
||||
.attr('transform', 'translate(100, 100)');
|
||||
|
||||
pieGraphData.append('path')
|
||||
.attr('d', pieArc)
|
||||
.attr('fill', d => pieColors(d.data.key))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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);
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,386 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca44
|
||||
title: Part 103
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Your chart needs some labels in each slice. On a new line, append `text` elements to your `pieGraphData` variable.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/pieGraphData\s*\.\s*append\s*\((`|'|")text\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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);
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,403 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca47
|
||||
title: Part 104
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain a `text` function to set the text of each pie slice to a percentage. Set the value to a "d function" with curly brackets and leave the function empty for now. It should look like this:
|
||||
|
||||
```js
|
||||
.text(d => {
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
The method for getting the percent of each slice will take a few steps:
|
||||
|
||||
1. Find the total number of followers for the displayed year
|
||||
2. Divide the followers of a single platform by that total
|
||||
3. Turn it into a string to display
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.append\('text'\)\s*\.text\s*\(\s*d\s*=>\s*\{\s*\}\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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 => {
|
||||
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,400 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca48
|
||||
title: Part 105
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In the function you just created, create a `const` named `values`. Use the `d3.values` function to get the values of the 2020 followers and set the result to your `values` variable. Here's how to get the values:
|
||||
|
||||
```js
|
||||
d3.values(data[8].followers)
|
||||
```
|
||||
|
||||
It will be an array with the values of the followers for the three platforms in 2020.
|
||||
|
||||
Note that this "d function" has curly brackets. So you could `console.log(values)` in there to see it's value.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*values\s*=\s*d3\s*\.\s*values\s*\(\s*data\s*\[\s*8\s*\]\s*\.\s*followers\s*\);?/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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 => {
|
||||
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,393 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca49
|
||||
title: Part 106
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Since you want to find what percent each of those `values` is, you first need to add them all up. `d3.sum` will do that for you. Create a new `const` named `sum` and set it equal to `d3.sum(values)`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*sum\s*=\s*d3\s*\.\s*sum\s*\(\s*values\s*\)\s*;?/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,395 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4a
|
||||
title: Part 107
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create another variable named `percent` and set it equal to `d.data.value` divided by your `sum` variable.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*percent\s*=\s*d\s*\.\s*data\s*\.\s*value\s*\/\s*sum;?/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,405 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4b
|
||||
title: Part 108
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Your percent values are numbers less than one. You will need to multiply it by 100, round of the decimals, and add a `%` sign. Use a template literal to return this to the `text` function:
|
||||
|
||||
```js
|
||||
${Math.round(percent * 100)}%
|
||||
```
|
||||
|
||||
Don't forget that you need a `return` statement here since you aren't using an implicit return.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/return\s*`\$\{\s*Math\s*\.\s*round\s*\(\s*percent\s*\*\s*100\s*\)\s*\}%`;?\s*\}\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
return `${ Math.round(percent*100) }%`;
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,404 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4c
|
||||
title: Part 109
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The text elements are at the center of the pie graph, you need to use the `centroid` from the D3 arc API to tell them where to go. Add an `attr` function to set the `transform` to a `d` function that returns this template literal: `translate(${ pieArc.centroid(d) })`
|
||||
|
||||
The `centroid` function will find the midpoint of each slice for each text element.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const transform = $('.dashboard div svg g text')[0].getAttribute('transform').replace('translate(','').replace(')','').split(','); assert(transform[0] < 39 && transform[1] > 31);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
return `${ Math.round(percent*100) }%`;
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
return `${ Math.round(percent*100) }%`;
|
||||
})
|
||||
.attr('transform', d => `translate(${pieArc.centroid(d)})`)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e8
|
||||
title: Part 11
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Later on, you will be adding more elements to the dashboard container. Set the `display` to `flex` and the `align-items` to `center` so those items will be vertically centered.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const dashboard = $(".dashboard"); assert(dashboard.css("display") === "flex" && dashboard.css("align-items") === "center");
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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;
|
||||
|
||||
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,406 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4d
|
||||
title: Part 110
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The function you just added, placed the start of the text at the midpoint of each slice. Change the `style` of the text to give it a `text-anchor` of `middle` so the middle of the text is in the middle of the slice.
|
||||
|
||||
After that, set the `font` to `10px verdana`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const text = $('.dashboard div svg g text')[0]; assert(text.style.textAnchor === 'middle' && text.style.font.toLowerCase() === '10px verdana');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].followers);
|
||||
const sum = d3.sum(values);
|
||||
const percent = d.data.value/sum;
|
||||
return `${ Math.round(percent*100) }%`;
|
||||
})
|
||||
.attr('transform', d => `translate(${pieArc.centroid(d)})`)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,408 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4e
|
||||
title: Part 111
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The last component you are going to add is a legend to display the name of each platform and the number of followers for the year. Create a new `const` named `legend` and use it to `append` a `table` to your `rightDashboard` variable. This looks similar to the code where you created your `pieGraph` variable.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*legend\s*=\s*rightDashboard\s*\.\s*append\s*\(\s*('|"|`)\s*table\s*\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,412 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca4f
|
||||
title: Part 112
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Give the table a `width` of `200` and a `height` of `120` using `attr`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const table = $('.dashboard div table')[0]; assert(table.getAttribute('width') == 200 && table.getAttribute('height') == 120);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,415 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca50
|
||||
title: Part 113
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `font` to `12px verdana` using the `style` function.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table')[0].style.font.toLowerCase() === '12px verdana');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,418 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca51
|
||||
title: Part 114
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create a new `const` named `legendTitle` and use it to `append` a `thead` to your `legend` variable. `thead` is used with the HTML table element and is for the top row of the table.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*legendTitle\s*=\s*legend\s*\.\s*append\s*\(\s*('|"|`)\s*thead\s*\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,422 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca52
|
||||
title: Part 115
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`append` a `tr` element to the selection and then append a `th` element right after it. `tr` is for defining a row of the table, and `th` is for defining the header cells of the table.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table thead tr th').length === 1);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,425 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca53
|
||||
title: Part 116
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the `text` function to set the text of the selection to `2020 followers`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table thead tr th').text() === '2020 followers');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,427 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca54
|
||||
title: Part 117
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Your table is going to have three columns, one for the platform name, one for the color it is using on your dashboard, and a third to display the number of followers. So you want the title to take up all three columns. Set the `colspan` attribute of the `th` to `3` so it spans all three of these columns.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table thead tr th')[0].getAttribute('colspan') == 3);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,429 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca55
|
||||
title: Part 118
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create a new `const` named `legendRows` and use it to `append` a `tbody` element to your `legend` variable similar to how you added the `thead`. `tbody` is for the main content of an HTML table.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*legendRows\s*=\s*legend\s*\.\s*append\s*\(\s*('|"|`)\s*tbody\s*\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,434 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca56
|
||||
title: Part 119
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add a `selectAll` function to the selection and pass it the string `tr`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const legendRows = legend\.append\('tbody\s*'\)\s*\.\s*selectAll\s*\(\s*('|"|`)\s*tr\s*\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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.selectAll('pieSliceText')
|
||||
.data(pie(d3.entries(data[8].followers)))
|
||||
.enter()
|
||||
.append('text')
|
||||
.text(d => {
|
||||
const values = d3.values(data[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,99 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e9
|
||||
title: Part 12
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Back in the HTML file, add a `script` tag at the bottom of the head element and give it a `src` attribute of `./d3-5.9.2.min.js`. Don't forget the closing tag. This will add the D3 library to your project from a downloaded copy.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = code.match(/<script\s+[\s\S]+?[^>]>\s*<\/script\s*>/gi)[0]; assert(/src\s*=\s*('|")\s*(\.\/)?d3-5.9.2.min.js\s*\1/gi.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
<script src="./d3-5.9.2.min.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,434 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca57
|
||||
title: Part 120
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the `data` function to set the data for the rows to an array of your 2020 followers. To get the array use `d3.entries(data[8].followers)`. Remember, this will create an array of key/value pairs of your followers for that year.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.selectAll\('tr'\)\s*\.\s*data\s*\(\s*d3\s*\.\s*entries\s*\(\s*data\s*\[\s*8\s*\]\s*\.\s*followers\s*\)\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,439 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca58
|
||||
title: Part 121
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add the `enter` and `append` functions to the selection. Pass the string `tr` to the append function to add three table row elements. These elements will be for displaying each platform's name.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr').length === 3);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,443 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca59
|
||||
title: Part 122
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, `append` a `td` to your `legendRows` variable. `td` is for an individual cell in the row of the table.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td').length === 3);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,445 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5a
|
||||
title: Part 123
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the `text` function to set the text of each `td` to the `key` of each data point by using a "d function" to return `d.key`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td').text() === 'twittertumblrinstagram');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,448 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5b
|
||||
title: Part 124
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
This is the first column of your table. Set the `align` attribute to `right` to align the text to the right of each cell.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td')[0].getAttribute('align').toLowerCase() === 'right');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,451 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5c
|
||||
title: Part 125
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, append another `td` element to your `legendRows` variable. This will be for colored squares in the center column.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td').length === 6);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,454 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5d
|
||||
title: Part 126
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `align` attribute to `center`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td')[1].getAttribute('align').toLowerCase() === 'center');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
.attr('align', 'center')
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,456 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5e
|
||||
title: Part 127
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Append a `div` element to the selection. Each `div` will be a small square for each color.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td div').length === 3);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
.attr('align', 'center')
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
.attr('align', 'center')
|
||||
.append('div')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,458 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca5f
|
||||
title: Part 128
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `width` to `16px` and the `height` to `16px` using the `style` function.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const div = $('.dashboard div table tbody tr td div')[0]; assert(div.style.width == '16px' && div.style.height === '16px');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].followers))
|
||||
.enter()
|
||||
.append('tr');
|
||||
|
||||
legendRows.append('td')
|
||||
.text(d => d.key)
|
||||
.attr('align', 'right');
|
||||
|
||||
legendRows.append('td')
|
||||
.attr('align', 'center')
|
||||
.append('div')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,461 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca60
|
||||
title: Part 129
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Using the `style` function again, set the `background-color` of each div to a "d function". Using the "d function", pass the key(`d.key`) of each data point to your `pieColors` scale so it knows what color to use.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td div')[0].style.backgroundColor === 'rgb(124, 217, 209)');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ea
|
||||
title: Part 13
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add another `script` below the one you just added. Give it a `src` attribute of `./data.js`.
|
||||
|
||||
This adds a `data` variable to your project that contains your number of social media followers, it is an array of objects. Each object has the year and your followers for three different platforms. You will see what it looks like shortly.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = code.match(/<script\s+[\s\S]+?[^>]>\s*<\/script\s*>/gi)[1]; assert(/src\s*=\s*('|")\s*(\.\/)?data.js\s*\1/gi.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
<script src="./d3-5.9.2.min.js"></script>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
<script src="./d3-5.9.2.min.js"></script>
|
||||
<script src="./data.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,464 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca61
|
||||
title: Part 130
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, append another `td` to the `legendRows` variable for the last group of items. It will display the number of followers for each platform.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td').length === 9);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,467 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca62
|
||||
title: Part 131
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `text` to a "d function" that returns the value(`d.value`) for each data point.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td')[2].innerHTML === '2845');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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')
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,467 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca63
|
||||
title: Part 132
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `align` attribute to `left` for this selection.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.dashboard div table tbody tr td')[2].getAttribute('align').toLowerCase() === 'left');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,468 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca64
|
||||
title: Part 133
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The legend has all the information is needs, but the title looks a little misaligned. Go to where you created your `legendTitle` variable and set the `position` to `relative` and the `left` to `20px` using `style` functions.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const th = $('.dashboard div table thead tr th')[0]; assert(th.style.position === 'relative' && th.style.left === '20px');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
const legendTitle = legend.append('thead')
|
||||
.append('tr')
|
||||
.append('th')
|
||||
.text('2020 followers')
|
||||
.attr('colspan', 3)
|
||||
|
||||
|
||||
const legendRows = legend.append('tbody')
|
||||
.selectAll('tr')
|
||||
.data(d3.entries(data[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
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[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,473 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca65
|
||||
title: Part 134
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The legend and pie graph look a little off as well. Go to where you created your `legend` variable and add a `position` of `relative` and a `top` of `30px` using `style` functions.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const table = $('.dashboard div table')[0]; assert(table.style.position === 'relative' && table.style.top === '30px');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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')
|
||||
|
||||
|
||||
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[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,482 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca66
|
||||
title: Part 135
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Lastly, where you created your `pieGraph` variable, add a `position` of `relative` and a `left` of `20px` using `style` functions.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const pieGraph = $('.dashboard div svg')[0]; assert(pieGraph.style.position === 'relative' && pieGraph.style.left === '20px');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
const pieArc = d3.arc()
|
||||
.outerRadius(100)
|
||||
.innerRadius(0);
|
||||
|
||||
const pieColors = d3.scaleOrdinal()
|
||||
.domain(data[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
|
||||
|
||||
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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,491 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca67
|
||||
title: Part 136
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Finally! You have all the elements displayed and they look good. The last thing you will do is make it so you can see the data from whatever year you want.
|
||||
|
||||
Wrap all the code in the script you've been working with in a function named `drawDashboard` and give it a parameter named `year`. Then, at the bottom of the script, call the function you created and pass it the number `2020`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(typeof(drawDashboard) === 'function' && /<\/script>\s*<script>\s*function\s*drawDashboard\s*\(\s*year\s*\)\s*\{/g.test(code) && /\}\s*drawDashboard\s*\(\s*2020\s*\)\s*;?\s*<\/script>\s*$/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
|
||||
|
||||
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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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');
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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 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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,500 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca68
|
||||
title: Part 137
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
At the top of the function create a new `const` named `index`. You are going to use it to find the item in the `data` array with the year that is passed to the function.
|
||||
|
||||
Use JavaScript's `findIndex` function to set your `index` variable to the index of the item in the `data` array where the year is the same as the year passed to your `drawDashboard` function. Here's an example:
|
||||
|
||||
```js
|
||||
array.findIndex(d =>
|
||||
// find the index where the year passed to
|
||||
// drawDashboard equals the year of the array
|
||||
)
|
||||
```
|
||||
|
||||
After this, you will be able to use `data[index]` to get that item in the array.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = $('.dashboard').siblings('script')[1].innerHTML; assert(/var index = data.findIndex\(function \(d\) \{\s*return (year === d\.year|d.year === year);\s*\}\);/g.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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 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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,499 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6a
|
||||
title: Part 138
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
There are four places in the file where you used `data[8]` to set data to the year 2020. Change all five of them to `data[index]` so you can pass in any year to the function to display the data from that year.
|
||||
|
||||
The five spots are:
|
||||
|
||||
1. The `domain` for `pieColors`.
|
||||
2. The `data` for `pieGraphData`.
|
||||
3. The `text` for your pie slice text.
|
||||
4. The `data` for your `legendRows`.
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(!/data\[8\]/g.test(code) && code.match(/data\s*\[\s*index\s*\]/g).length === 4);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
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[8].followers)
|
||||
.range([twitterColor, tumblrColor, instagramColor]);
|
||||
|
||||
const pie = d3.pie()
|
||||
.value(d => d.value);
|
||||
|
||||
const pieGraphData = pieGraph.selectAll('pieSlices')
|
||||
.data(pie(d3.entries(data[8].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[8].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[8].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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,501 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6b
|
||||
title: Part 139
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Go to where you `call` the `xAxis` and create a `mouseover` event for the labels. Chain the `on` function to them, pass it the string `mouseover`, and give it a value of a "d function" that calls `drawDashboard` with `d` as the argument. It will look like this:
|
||||
|
||||
```js
|
||||
.on('mouseover', d => drawDashboard(d))
|
||||
```
|
||||
|
||||
So now, when you hover a label, the function will be called with the year that is being hovered.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = $('.dashboard').siblings('script')[1].innerHTML; assert(/\.on\(('|"|`)mouseover\1, function \(d\) \{\s*return drawDashboard\(d\);\s*\}\)/g.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9eb
|
||||
title: Part 14
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add a third script just before the closing body tag. It will be the JavaScript file you will use to create the rest of the dashboard. Give the script a `src` of `./dashboard.js`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = code.match(/<script\s+[\s\S]+?[^>]>\s*<\/script\s*>/gi)[2]; assert(/src\s*=\s*('|")\s*(\.\/)?dashboard.js\s*\1/gi.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
<script src="./d3-5.9.2.min.js"></script>
|
||||
<script src="./data.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
<script src="./d3-5.9.2.min.js"></script>
|
||||
<script src="./data.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
|
||||
<script src="dashboard.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,498 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6c
|
||||
title: Part 140
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='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.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = $('.dashboard').siblings('script')[1].innerHTML; assert(/d3\.select\(('|"|`)\.dashboard\1\)\.html\(('|"|`)\2\)/g.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,507 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6d
|
||||
title: Part 141
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Now when you hover a label, you can see the data for the different years.
|
||||
|
||||
Where you created the `text` elements for the x-axis labels, change the `font` to `bold 10px verdana` for the currently displayed year.
|
||||
|
||||
To do this, create a "d function" in the `font` value area and return the above sting if `d` equals `year`. Otherwise, return the string that is currently there (`10px verdana`). It's easiest to use a ternary operator for this.
|
||||
|
||||
Here's a hint:
|
||||
|
||||
```js
|
||||
.style('font', d => d === year ? )
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(Object.values($('.dashboard svg g text')).filter(el => el.style && el.style.font.toLowerCase() === 'bold 10px verdana').length === 1);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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', '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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,497 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6e
|
||||
title: Part 142
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create another `mouseover` event for when you hover one of the `twitter-circles`. It will look like the other `mouseover` event you created except the `drawDashboard` function will take `d.year` instead of `d`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = $('.dashboard').siblings('script')[1].innerHTML; assert(/\.on\(('|"|`)mouseover\1, function \(d\) \{\s*return drawDashboard\(d\.year\);\s*\}\)/g.test(script));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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', '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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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', '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')
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,500 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca6f
|
||||
title: Part 143
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Similar to how you made the text bold for the label of the displayed year; change the `fill` of the `twitter-circles` to your `twitterColor` for the currently displayed year. To do this, use a "d function" that returns the `twitterColor` when `d.year` equals `year`, and leave it `white` if it doesn't.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(Object.values($('.dashboard svg circle')).filter(el => el.getAttribute && el.getAttribute('fill') === '#7cd9d1').length === 1);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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', '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')
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,506 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca70
|
||||
title: Part 144
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add a `mouseover` event to the `tumblr-circles` and `instagram-circles` in the same way that you did for the `twitter-circles`.
|
||||
|
||||
After that, you will be able hover any of the circles or year labels to get the information for that year.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const script = $('.dashboard').siblings('script')[1].innerHTML; assert(script.match(/\.on\(('|"|`)mouseover\1, function \(d\) \{\s*return drawDashboard\(d\.year\);\s*\}\)/g).length === 3);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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')
|
||||
|
||||
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,506 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca71
|
||||
title: Part 145
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='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.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
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);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,504 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca72
|
||||
title: Part 146
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The last thing is that the legend title always shows 2020. Change the `text` of the `legendTitle` to a template literal that shows the currently displayed year followed by a space and `followers`.
|
||||
|
||||
That's it, your dashboard is finished! Don't forget to admire your hard work.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.text\s*\(\s*`\s*\$\{\s*year\s*\} followers`\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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(`${year} 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>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ec
|
||||
title: Part 15
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The script at the top is the `data.js` file you added. I have placed it here so you can see the data and recommend taking a look at it. The second script is the one you just added and where you will build the rest of the project.
|
||||
|
||||
In the second script, create three `const` variables; `svgMargin` with a value of `70`, `svgWidth` with a value of `700`, and `svgHeight` equal to `500`. The first part of the dashboard will be a line graph. It will use these variables as its dimensions.
|
||||
|
||||
The line graph will have the years from your data variable across the bottom, and a scale on the left to show the numbers of followers. Each platform will have a line going across the graph that shows how many followers you had for each year.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(svgMargin === 70 && svgWidth === 700 && svgHeight === 500);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500;
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,125 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ed
|
||||
title: Part 16
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add three more variables; `twitterColor` with a value of `#7cd9d1`, `tumblrColor` equal to `#f6dd71`, and `instagramColor` at `#fd9b98`. Make sure those Hex values are strings. These will be colors used to represent the different platforms throughout the project.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(twitterColor === '#7cd9d1' && tumblrColor === '#f6dd71' && instagramColor === '#fd9b98');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500;
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ee
|
||||
title: Part 17
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
When you added the D3 library earlier, it put an object named `d3` in your project with a bunch of functions. One of them is `select`; you can use dot notation to access this and the other functions from the object. Create a new variable named `lineGraph` and use `d3.select` to select the `.dashboard` element. Here's an example of something similar:
|
||||
|
||||
```js
|
||||
const variableName = d3.select('.className')
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(lineGraph._groups[0][0] === $(".dashboard")[0]);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,140 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ef
|
||||
title: Part 18
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Your dashboard element is now "selected". D3 has a number of functions for working with a selection; one of them is `append`. It is used to add an element. Chain the `append` function to your selection and use it to add an `svg` element. Here's an example of how that might be done:
|
||||
|
||||
```js
|
||||
const variableName = d3.select('selectedElement')
|
||||
.append('elementToAdd')
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(lineGraph._groups[0][0] === $("svg")[0]);
|
||||
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
.append('svg')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,145 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f0
|
||||
title: Part 19
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
You can't see it, but there is now an `svg` element nested in your dashboard container. When you appended it, it became the "selection" for this area of code. Any functions you chain after it will be used on this selection.
|
||||
|
||||
`attr` is a function to set attributes. You need to pass it the attribute you want to set, and the value you want to give it. Here's an example of how to chain `attr` to a selection:
|
||||
|
||||
```js
|
||||
const variableName = d3.select('element')
|
||||
.append('element')
|
||||
.attr('attribute', 'value')
|
||||
```
|
||||
|
||||
Chain an `attr` function to the selection that sets the `width` as the `svgWidth` variable you created earlier. When using a variable as a value, you do not need to put it in any kind of quotations.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("svg")[0].attributes.width.value === "700");
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
.append('svg')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
.append('svg')
|
||||
.attr('width', svgWidth)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,56 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9df
|
||||
title: Part 2
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Next, add opening and closing `html`, `head` and `body` tags below the doctype. Be sure to nest them properly.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/<!DOCTYPE\s+html\s*>\s*<html\s*>\s*<head\s*>\s*<\/head\s*>\s*<body\s*>\s*<\/body\s*>\s*<\/html\s*>/gi.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,137 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f1
|
||||
title: Part 20
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain another `attr` function that sets the `height` as the `svgHeight` variable you created.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("svg")[0].attributes.height.value === "500");
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
const svgMargin = 70,
|
||||
svgWidth = 700,
|
||||
svgHeight = 500,
|
||||
twitterColor = '#7cd9d1',
|
||||
tumblrColor = '#f6dd71',
|
||||
instagramColor = '#fd9b98';
|
||||
|
||||
const lineGraph = d3.select('.dashboard')
|
||||
.append('svg')
|
||||
.attr('width', svgWidth)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f2
|
||||
title: Part 21
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Your line graph needs some scales so it knows how to translate the data into visual distances. The first one is the scale for the y-axis. It will be to show the number of followers. D3 has many utilities for creating scales. You want to use it's `scaleLinear` method for this scale.
|
||||
|
||||
Create a new `const` named `yScale`, and set it equal to `d3.scaleLinear()`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(typeof(yScale) === "function" && /yScale\s*=\s*d3\.scaleLinear/.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f3
|
||||
title: Part 22
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
D3 has a bunch of functions for working with scales as well. One of them is `domain`. It takes an array that is used to describe the highest and lowest values of the data for this scale. After a quick look at the data, the values of the "followers" go from about 0 to 5000. Chain the `domain` function to the `yScale` and pass it the array `[0, 5000]`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const domain = yScale.domain(); assert(domain.length === 2 && domain[0] === 0 && domain[1] === 5000);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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])
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f4
|
||||
title: Part 23
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `range` function describes how to map the domain values for display on the graph. For example, a value of 5000 followers can't use 5000 as it y-coordinate on the SVG or it would be off the graph. You need to tell the range where the top and bottom of the graph is so the scale can give appropriate values for the y-coordinate.
|
||||
|
||||
Chain the `range` function below the `domain` and pass it an array with `svgHeight - svgMargin` and `svgMargin` as the values. That will translate to `[430, 70]`. This is where the top and bottom of the graph are. So a data point of 5000 followers will map to a value of 430 to use as its y-coordinate and 0 followers will use 70 as its y-coordinate. Any value in between will scale linearly.
|
||||
|
||||
Your graph will have a margin around it for things like axes and labels. The actual line data will display on the inside of this margin area, which is why you use those values. This will become more clear as you progress through the project.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const range = yScale.range(); assert(range.length === 2 && range[0] === 430 && range[1] === 70);
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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])
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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]);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f5
|
||||
title: Part 24
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create a new `const` named `xScale`. Use it to create another linear scale like you did for the y-scale. This will be the horizontal or "x" axis.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(typeof(xScale) === "function" && /xScale\s*=\s*d3\.scaleLinear/.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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]);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,151 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f6
|
||||
title: Part 25
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The `year` values of your data will be used for the x-scale. Chain the `domain` function to `xScale` and pass it an array with the first and last years of your data.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const domain = xScale.domain(); assert(domain.length === 2 && domain[0] === 2012 && domain[1] === 2020);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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])
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f7
|
||||
title: Part 26
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The range for this scale will go from the left of your graph to the right, with 2012 on the left and 2020 on the right. Add the `range` function to the `xScale` and pass it an array with the values: `svgMargin` and `svgWidth - svgMargin`. This will translate to `[70, 630]`. So 2012 will use 70 as is x-coordinate and 2020 will use 630 as its x-coordinate.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const range = xScale.range(); assert(range.length === 2 && range[0] === 70 && range[1] === 630);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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])
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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]);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f8
|
||||
title: Part 27
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The two scales you defined will be used to create the axes and lines. First is the y-axis, it will be a line with some labels on the left of the graph. Create a new `const` named `yAxis` and set it equal to `d3.axisLeft(yScale)`. This will use the information from the `yScale` variable to build the axis.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(typeof(yAxis) === "function" && /yAxis\s*=\s*d3\.axisLeft\(\s*yScale\)/.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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]);
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,160 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9f9
|
||||
title: Part 28
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Create a new `const` named `xAxis` and set the value equal to `d3.axisBottom(xScale)`. This will create another axis for the bottom of the graph using the information from `xScale`. Although the axes do not display yet, they have the information they need to display correctly.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(typeof(xAxis) === "function" && /xAxis\s*=\s*d3\.axisBottom\(\s*xScale\)/.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,164 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9fa
|
||||
title: Part 29
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, append a new `g` element to your `lineGraph` variable. `lineGraph.append('g')` will do that for you. This will add a `g` to your SVG and be for displaying the y-axis. `g` is an SVG element that stands for "group".
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("svg")[0].children[0] === $("g")[0] && $("g").length === 1);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,66 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e0
|
||||
title: Part 3
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In the head, add a `title` of `D3 Dashboard`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/<head\s*>\s*<title\s*>D3 Dashboard<\/title\s*>\s*<\/head\s*>/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,168 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9fb
|
||||
title: Part 30
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`call` is another function to use with selections. Chain a `call` function to the selection and pass your `yAxis` variable to it. This will draw your y-axis on the SVG.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($(".tick").length === 11 && /\.call\(\s*yAxis\s*\)/.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,172 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9fc
|
||||
title: Part 31
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
After all that work, something is finally displayed on the graph. It's the y-axis and all the numbers are hidden on the left.
|
||||
|
||||
Move the axis your `svgMargin` to the right by chaining an `attr` function to the selection. Use it to set the `transform` to `translate(${svgMargin}, 0)`. Use a template literal (backticks) to set the value so you can put your variable in there.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("g")[0].attributes.transform.nodeValue === "translate(70, 0)");
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,171 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9fd
|
||||
title: Part 32
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
`style` is a function similar to `attr`, but is more for manipulating CSS styles rather than element attributes. Add a `style` function to the selection that sets the `font` to `10px verdana`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: 'assert($("g")[0].attributes.style.nodeValue === "font: 10px verdana;");'
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,174 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9fe
|
||||
title: Part 33
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, append another `g` element to your `lineGraph` variable like you did before. This one will be for the x-axis.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("g").length === 13);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
lineGraph.append('g')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,177 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9ff
|
||||
title: Part 34
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Use the `call` function to draw the x-axis onto the SVG like you did for the y-axis.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('g').length === 22);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
lineGraph.append('g')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(xAxis)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca00
|
||||
title: Part 35
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The axis has the right size and labels, but needs to be moved down. Use the `attr` function to set the `transform` like you did before. This time move it down your `svgHeight` minus the `svgMargin`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("svg > g")[1].attributes.transform.nodeValue === "translate(0, 430)");
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(yAxis)
|
||||
.attr('transform', `translate(${svgMargin}, 0)`)
|
||||
.style('font', '10px verdana');
|
||||
|
||||
lineGraph.append('g')
|
||||
.call(xAxis)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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})`)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,186 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca01
|
||||
title: Part 36
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The axis labels are `text` elements within the `g`, you can use the `selectAll` function to select them. Chain the `selectAll` function to select the `text` elements in this group. You can do that like this:
|
||||
|
||||
```js
|
||||
.selectAll('element')
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.attr\('transform', `translate\(0, \$\{svgHeight - svgMargin\}\)`\)\s*\.selectAll\s*\(\s*('|"|`)text\1\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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})`)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,183 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca02
|
||||
title: Part 37
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
I want the text elements to be rotated slightly. Chain the `style` function to set the `transform` to `translate(-12px, 0) rotate(-50deg)`. This will put them at an angle.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.tick > text').filter((node, index) => index.style.transform === 'translate(-12px) rotate(-50deg)' || index.style.transform === 'translate(-12px, 0px) rotate(-50deg)').length === 9);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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)')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,185 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca03
|
||||
title: Part 38
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add another `style` function to set the `text-anchor` to `end`. This will change the spot that each text element rotates around to the `end` of the element so they will align better.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.tick > text').filter((node, index) => index.style['text-anchor'] === 'end').length === 9);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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)')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,189 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca04
|
||||
title: Part 39
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add two more `style` functions; one to set the `cursor` to `pointer`, and another to set the `font` to `10px verdana`.
|
||||
|
||||
You will add some hover effects later, so the pointer will make for a better experience.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('.tick > text').filter((node, index) => index.style.cursor === 'pointer' && index.style.font === '10px verdana').length === 9);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e1
|
||||
title: Part 4
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Below the title, link to your external stylesheet by adding a `link` element with a `rel` attribute of `stylesheet` and an `href` attribute of `./dashboard.css`. Remember that link elements do not need a closing tag. You will be adding some styles to this file shortly.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const link = code.match(/<link\s+[\s\S]+?[^>]>/gi)[0]; assert(/rel\s*=\s*('|")\s*stylesheet\s*\1/gi.test(link) && /href\s*=\s*('|")\s*(.\/)?dashboard\.css\s*\1/gi.test(link));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,191 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca05
|
||||
title: Part 40
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
There are a number of D3 functions to work with how the "ticks" or your axis labels are displayed; one of them is `ticks`. Go back to where you defined the `yAxis` variable and chain a `ticks` function to it and pass it these two arguments: `6, '~s'`.
|
||||
|
||||
The `6` will set the number of ticks used to 6, and the `~s` will make the labels display the number of thousands followed by a `k`. For example, `4000` will become `4k`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const ticks = $('.tick > text'); assert(ticks[0].innerHTML === '0k' && ticks[1].innerHTML === '1k' && ticks[2].innerHTML === '2k' && ticks[3].innerHTML === '3k' && ticks[4].innerHTML === '4k' && ticks[5].innerHTML === '5k');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
const xAxis = d3.axisBottom(xScale)
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,191 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca06
|
||||
title: Part 41
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Go back to where you defined your `xAis` variable and chain the `tickFormat` function to it. Pass it `d3.format('')`. This will remove the commas in the year labels of the x-axis.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const ticks = $('.tick > text'); assert(ticks[6].innerHTML === '2012' && ticks[14].innerHTML === '2020');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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)
|
||||
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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(''))
|
||||
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca07
|
||||
title: Part 42
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
In the same spot, chain the `tickPadding` function to the `xAxis` and pass it `10`. This will add a little padding to the ticks so the labels are better aligned.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.tickFormat\(d3\.format\((''\)\)\s*\.tickPadding\s*\(\s*10\s*\))/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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(''))
|
||||
|
||||
|
||||
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');
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,199 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca08
|
||||
title: Part 43
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The axes and labels are looking good. Next, you will start to add some of the lines for the data. First is the line for the Twitter data. On a new line, create a new `const` named `twitterLine` and set it equal to `d3.line()`. `line` is a D3 function for creating a line.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*twitterLine\s*=\s*d3\s*\.\s*line\s*\(\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca09
|
||||
title: Part 44
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The line needs x and y values for each point of data. Chain `x` to the line and pass it a "d function". Here's how that will look:
|
||||
|
||||
```js
|
||||
.x(d => d.year)
|
||||
```
|
||||
|
||||
You will be passing your `data` array to this line function, where it will go through each item in the array(`d`) and create an x value based on the year(`d.year`).
|
||||
|
||||
This is the first place you have seen a "d function". These are common in D3 and that is how I will refer to them throughout this project.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const twitterLine = d3\.line\(\)\s*\.x\s*\(\s*d\s*=>\s*d\.year\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => d.year)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,204 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0a
|
||||
title: Part 45
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Instead of simply using the year(`d.year`) for the x-coordinate, you need to pass each year to the `xScale` so it can set the appropriate coordinate based on your scale.
|
||||
|
||||
In the "d function" you created, return `xScale(d.year)` instead of `d.year`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.x\s*\(d\s*=>\s*xScale\s*\(\s*d\.year\s*\)\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => d.year)
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,208 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0b
|
||||
title: Part 46
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Chain the `y` function to the line and pass it a "d function" that returns your `yScale` with `d.followers.twitter` as its argument.
|
||||
|
||||
This is similar to how you set the x values. It will use the values of your Twitter followers and your `yScale` to set the y coordinate for each item.
|
||||
|
||||
These "d functions" use implicit returns. But if you add curly brackets and a return statement, you can put any JavaScript in there that you want. Including `console.log` statements that can be useful for debugging.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.y\s*\(\s*d\s*=>\s*yScale\s*\(\s*d\.followers.twitter\s*\)\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,207 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0c
|
||||
title: Part 47
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
The first line is created and ready to be displayed, which will take a couple steps. On a new line, `append` a `path` element to your `lineGraph` variable. This is similar to how you appended the `g` before.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('svg path').length === 3 && /lineGraph\.append\((`|'|")path\1\)/gi.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
lineGraph.append('path')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,214 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0d
|
||||
title: Part 48
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Tell the path what data to use. Add an `attr` function and set the `d` to `twitterLine(data)`. This will the build the path using the `twitterLine` function you created and your data variable.
|
||||
|
||||
Note that the `d` in this case is a path attribute for drawing a line and is different from a "d function".
|
||||
|
||||
After you have added your code, take a look at the data flow to help understand what is happening. You pass the data array to your `twitterLine` function where it sets the x and y values using your "d functions". The "d functions" go through each item in the array, passing part of the item to each scale to find the appropriate coordinates. When it's done, the value you are setting here is created and sent back. The result ends up being a confusing string of numbers and coordinates to tell the path how to be drawn.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('svg path')[2].getAttribute('d').length === 151);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
lineGraph.append('path')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
lineGraph.append('path')
|
||||
.attr('d', twitterLine(data))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,215 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0e
|
||||
title: Part 49
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Add three more `attr` functions to the path; one to set the `stroke` to your `twitterColor` variable, another to set the `stroke-width` to `3`, and a third to set the `fill` to `transparent`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: const twitterPath = $('svg path')[2]; assert(twitterPath.getAttribute('stroke') === '#7cd9d1' && twitterPath.getAttribute('stroke-width') == '3' && twitterPath.getAttribute('fill') === 'transparent');
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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');
|
||||
|
||||
const twitterLine = d3.line()
|
||||
.x(d => xScale(d.year))
|
||||
.y(d => yScale(d.followers.twitter));
|
||||
|
||||
lineGraph.append('path')
|
||||
.attr('d', twitterLine(data))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,72 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1c9e2
|
||||
title: Part 5
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Next, add a container for the dashboard. Put an empty `div` element in the body with class of `dashboard`. You will be appending all the dashboard elements to this div.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($("div.dashboard").length === 1);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>D3 Dashboard</title>
|
||||
<link rel="stylesheet" href="./dashboard.css">
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="dashboard"></div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,219 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca0f
|
||||
title: Part 50
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, create a new `const` named `tumblrLine` and set it equal to `d3.line()`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const\s*tumblrLine\s*=\s*d3\s*\.\s*line\s*\(\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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');
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,221 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca10
|
||||
title: Part 51
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `x` values for `tumblrLine` using another "d function". Use your `xScale` and the `d.year` to calculcate their values just like you did for the Twitter line.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/const tumblrLine = d3\.line\(\)\s*\.x\s*\(\s*d\s*=>\s*xScale\s*\(\s*d\.year\s*\)\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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()
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,226 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca11
|
||||
title: Part 52
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Set the `y` values for `tumblrLine` using a "d function" again. Use your `yScale` and `d.followers.tumblr` to calculcate their values just like you did for the Twitter line.
|
||||
|
||||
The x values for each line will be the same, but the y values will use the data from the different platforms.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert(/\.y\s*\(\s*d\s*=>\s*yScale\s*\(\s*d\.followers.tumblr\s*\)\s*\)/g.test(code));
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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))
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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));
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,227 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca12
|
||||
title: Part 53
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
On a new line, `append` a `path` element to the `lineGraph` variable. This one will be for displaying the `tumblrLine`.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('svg path').length === 4 && code.match(/lineGraph\.append\((`|'|")path\1\)/gi).length === 2);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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));
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
@@ -0,0 +1,230 @@
|
||||
---
|
||||
id: 5d8a4cfbe6b6180ed9a1ca13
|
||||
title: Part 54
|
||||
challengeType: 0
|
||||
isBeta: true
|
||||
---
|
||||
|
||||
## Description
|
||||
<section id='description'>
|
||||
|
||||
Tell the new path how to be drawn by setting the `d` attribute to `tumblrLine(data)` using the `attr` function.
|
||||
</section>
|
||||
|
||||
## Instructions
|
||||
<section id='instructions'>
|
||||
</section>
|
||||
|
||||
## Tests
|
||||
<section id='tests'>
|
||||
|
||||
```yml
|
||||
tests:
|
||||
- text: test-text
|
||||
testString: assert($('svg path')[3].getAttribute('d').length === 115);
|
||||
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
## Challenge Seed
|
||||
<section id='challengeSeed'>
|
||||
<div id='html-seed'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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')
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
### Before Test
|
||||
<div id='html-setup'>
|
||||
|
||||
```html
|
||||
<!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>
|
||||
```
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
## Solution
|
||||
<section id='solution'>
|
||||
|
||||
```html
|
||||
<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>
|
||||
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')
|
||||
|
||||
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))
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
</section>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user