chore(i8n,learn): processed translations
This commit is contained in:
committed by
Mrugesh Mohapatra
parent
15047f2d90
commit
e5c44a3ae5
@ -0,0 +1,53 @@
|
||||
---
|
||||
id: bd7168d8c242eddfaeb5bd13
|
||||
title: Visualize Data with a Bar Chart
|
||||
challengeType: 3
|
||||
forumTopicId: 301464
|
||||
dashedName: visualize-data-with-a-bar-chart
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/GrZVaM>.
|
||||
|
||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||
|
||||
You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <https://github.com/d3/d3/blob/master/API.md#axes-d3-axis>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.
|
||||
|
||||
**User Story #1:** My chart should have a title with a corresponding `id="title"`.
|
||||
|
||||
**User Story #2:** My chart should have a `g` element x-axis with a corresponding `id="x-axis"`.
|
||||
|
||||
**User Story #3:** My chart should have a `g` element y-axis with a corresponding `id="y-axis"`.
|
||||
|
||||
**User Story #4:** Both axes should contain multiple tick labels, each with the corresponding `class="tick"`.
|
||||
|
||||
**User Story #5:** My chart should have a `rect` element for each data point with a corresponding `class="bar"` displaying the data.
|
||||
|
||||
**User Story #6:** Each bar should have the properties `data-date` and `data-gdp` containing date and GDP values.
|
||||
|
||||
**User Story #7:** The bar elements' `data-date` properties should match the order of the provided data.
|
||||
|
||||
**User Story #8:** The bar elements' `data-gdp` properties should match the order of the provided data.
|
||||
|
||||
**User Story #9:** Each bar element's height should accurately represent the data's corresponding GDP.
|
||||
|
||||
**User Story #10:** The `data-date` attribute and its corresponding bar element should align with the corresponding value on the x-axis.
|
||||
|
||||
**User Story #11:** The `data-gdp` attribute and its corresponding bar element should align with the corresponding value on the y-axis.
|
||||
|
||||
**User Story #12:** I can mouse over an area and see a tooltip with a corresponding `id="tooltip"` which displays more information about the area.
|
||||
|
||||
**User Story #13:** My tooltip should have a `data-date` property that corresponds to the `data-date` of the active area.
|
||||
|
||||
Here is the dataset you will need to complete this project: `https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json`
|
||||
|
||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`.
|
||||
|
||||
Once you're done, submit the URL to your working project with all its tests passing.
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,52 @@
|
||||
---
|
||||
id: 587d7fa6367417b2b2512bbf
|
||||
title: Visualize Data with a Choropleth Map
|
||||
challengeType: 3
|
||||
forumTopicId: 301465
|
||||
dashedName: visualize-data-with-a-choropleth-map
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/EZKqza>.
|
||||
|
||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||
|
||||
You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.
|
||||
|
||||
**User Story #1:** My choropleth should have a title with a corresponding `id="title"`.
|
||||
|
||||
**User Story #2:** My choropleth should have a description element with a corresponding `id="description"`.
|
||||
|
||||
**User Story #3:** My choropleth should have counties with a corresponding `class="county"` that represent the data.
|
||||
|
||||
**User Story #4:** There should be at least 4 different fill colors used for the counties.
|
||||
|
||||
**User Story #5:** My counties should each have `data-fips` and `data-education` properties containing their corresponding fips and education values.
|
||||
|
||||
**User Story #6:** My choropleth should have a county for each provided data point.
|
||||
|
||||
**User Story #7:** The counties should have data-fips and data-education values that match the sample data.
|
||||
|
||||
**User Story #8:** My choropleth should have a legend with a corresponding `id="legend"`.
|
||||
|
||||
**User Story #9:** There should be at least 4 different fill colors used for the legend.
|
||||
|
||||
**User Story #10:** I can mouse over an area and see a tooltip with a corresponding `id="tooltip"` which displays more information about the area.
|
||||
|
||||
**User Story #11:** My tooltip should have a `data-education` property that corresponds to the `data-education` of the active area.
|
||||
|
||||
Here are the datasets you will need to complete this project:
|
||||
|
||||
- **US Education Data:**`https://cdn.freecodecamp.org/testable-projects-fcc/data/choropleth_map/for_user_education.json`
|
||||
- **US County Data:**`https://cdn.freecodecamp.org/testable-projects-fcc/data/choropleth_map/counties.json`
|
||||
|
||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||
|
||||
Once you're done, submit the URL to your working project with all its tests passing.
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,61 @@
|
||||
---
|
||||
id: bd7188d8c242eddfaeb5bd13
|
||||
title: Visualize Data with a Heat Map
|
||||
challengeType: 3
|
||||
forumTopicId: 301466
|
||||
dashedName: visualize-data-with-a-heat-map
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/JEXgeY>.
|
||||
|
||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||
|
||||
You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.
|
||||
|
||||
**User Story #1:** My heat map should have a title with a corresponding `id="title"`.
|
||||
|
||||
**User Story #2:** My heat map should have a description with a corresponding `id="description"`.
|
||||
|
||||
**User Story #3:** My heat map should have an x-axis with a corresponding `id="x-axis"`.
|
||||
|
||||
**User Story #4:** My heat map should have a y-axis with a corresponding `id="y-axis"`.
|
||||
|
||||
**User Story #5:** My heat map should have `rect` elements with a `class="cell"` that represent the data.
|
||||
|
||||
**User Story #6:** There should be at least 4 different fill colors used for the cells.
|
||||
|
||||
**User Story #7:** Each cell will have the properties `data-month`, `data-year`, `data-temp` containing their corresponding month, year, and temperature values.
|
||||
|
||||
**User Story #8:** The `data-month`, `data-year` of each cell should be within the range of the data.
|
||||
|
||||
**User Story #9:** My heat map should have cells that align with the corresponding month on the y-axis.
|
||||
|
||||
**User Story #10:** My heat map should have cells that align with the corresponding year on the x-axis.
|
||||
|
||||
**User Story #11:** My heat map should have multiple tick labels on the y-axis with the full month name.
|
||||
|
||||
**User Story #12:** My heat map should have multiple tick labels on the x-axis with the years between 1754 and 2015.
|
||||
|
||||
**User Story #13:** My heat map should have a legend with a corresponding `id="legend"`.
|
||||
|
||||
**User Story #14:** My legend should contain `rect` elements.
|
||||
|
||||
**User Story #15:** The `rect` elements in the legend should use at least 4 different fill colors.
|
||||
|
||||
**User Story #16:** I can mouse over an area and see a tooltip with a corresponding `id="tooltip"` which displays more information about the area.
|
||||
|
||||
**User Story #17:** My tooltip should have a `data-year` property that corresponds to the `data-year` of the active area.
|
||||
|
||||
Here is the dataset you will need to complete this project: `https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json`
|
||||
|
||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||
|
||||
Once you're done, submit the URL to your working project with all its tests passing.
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,57 @@
|
||||
---
|
||||
id: bd7178d8c242eddfaeb5bd13
|
||||
title: Visualize Data with a Scatterplot Graph
|
||||
challengeType: 3
|
||||
forumTopicId: 301467
|
||||
dashedName: visualize-data-with-a-scatterplot-graph
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/bgpXyK>.
|
||||
|
||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||
|
||||
You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <https://github.com/d3/d3/blob/master/API.md#axes-d3-axis>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.
|
||||
|
||||
**User Story #1:** I can see a title element that has a corresponding `id="title"`.
|
||||
|
||||
**User Story #2:** I can see an x-axis that has a corresponding `id="x-axis"`.
|
||||
|
||||
**User Story #3:** I can see a y-axis that has a corresponding `id="y-axis"`.
|
||||
|
||||
**User Story #4:** I can see dots, that each have a class of `dot`, which represent the data being plotted.
|
||||
|
||||
**User Story #5:** Each dot should have the properties `data-xvalue` and `data-yvalue` containing their corresponding x and y values.
|
||||
|
||||
**User Story #6:** The `data-xvalue` and `data-yvalue` of each dot should be within the range of the actual data and in the correct data format. For `data-xvalue`, integers (full years) or Date objects are acceptable for test evaluation. For `data-yvalue` (minutes), use Date objects.
|
||||
|
||||
**User Story #7:** The `data-xvalue` and its corresponding dot should align with the corresponding point/value on the x-axis.
|
||||
|
||||
**User Story #8:** The `data-yvalue` and its corresponding dot should align with the corresponding point/value on the y-axis.
|
||||
|
||||
**User Story #9:** I can see multiple tick labels on the y-axis with `%M:%S` time format.
|
||||
|
||||
**User Story #10:** I can see multiple tick labels on the x-axis that show the year.
|
||||
|
||||
**User Story #11:** I can see that the range of the x-axis labels are within the range of the actual x-axis data.
|
||||
|
||||
**User Story #12:** I can see that the range of the y-axis labels are within the range of the actual y-axis data.
|
||||
|
||||
**User Story #13:** I can see a legend containing descriptive text that has `id="legend"`.
|
||||
|
||||
**User Story #14:** I can mouse over an area and see a tooltip with a corresponding `id="tooltip"` which displays more information about the area.
|
||||
|
||||
**User Story #15:** My tooltip should have a `data-year` property that corresponds to the `data-xvalue` of the active area.
|
||||
|
||||
Here is the dataset you will need to complete this project: `https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/cyclist-data.json`
|
||||
|
||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||
|
||||
Once you're done, submit the URL to your working project with all its tests passing.
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,53 @@
|
||||
---
|
||||
id: 587d7fa6367417b2b2512bc0
|
||||
title: Visualize Data with a Treemap Diagram
|
||||
challengeType: 3
|
||||
forumTopicId: 301468
|
||||
dashedName: visualize-data-with-a-treemap-diagram
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: <https://codepen.io/freeCodeCamp/full/KaNGNR>.
|
||||
|
||||
Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
|
||||
|
||||
You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <https://github.com/d3/d3/blob/master/API.md#axes-d3-axis>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.
|
||||
|
||||
**User Story #1:** My tree map should have a title with a corresponding `id="title"`.
|
||||
|
||||
**User Story #2:** My tree map should have a description with a corresponding `id="description"`.
|
||||
|
||||
**User Story #3:** My tree map should have `rect` elements with a corresponding `class="tile"` that represent the data.
|
||||
|
||||
**User Story #4:** There should be at least 2 different fill colors used for the tiles.
|
||||
|
||||
**User Story #5:** Each tile should have the properties `data-name`, `data-category`, and `data-value` containing their corresponding name, category, and value.
|
||||
|
||||
**User Story #6:** The area of each tile should correspond to the data-value amount: tiles with a larger data-value should have a bigger area.
|
||||
|
||||
**User Story #7:** My tree map should have a legend with corresponding `id="legend"`.
|
||||
|
||||
**User Story #8:** My legend should have `rect` elements with a corresponding `class="legend-item"`.
|
||||
|
||||
**User Story #9:** The `rect` elements in the legend should use at least 2 different fill colors.
|
||||
|
||||
**User Story #10:** I can mouse over an area and see a tooltip with a corresponding `id="tooltip"` which displays more information about the area.
|
||||
|
||||
**User Story #11:** My tooltip should have a `data-value` property that corresponds to the `data-value` of the active area.
|
||||
|
||||
For this project you can use any of the following datasets:
|
||||
|
||||
- **Kickstarter Pledges:** `https://cdn.freecodecamp.org/testable-projects-fcc/data/tree_map/kickstarter-funding-data.json`
|
||||
- **Movie Sales:** `https://cdn.freecodecamp.org/testable-projects-fcc/data/tree_map/movie-data.json`
|
||||
- **Video Game Sales:** `https://cdn.freecodecamp.org/testable-projects-fcc/data/tree_map/video-game-sales-data.json`
|
||||
|
||||
You can build your project by forking [this CodePen pen](https://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
|
||||
|
||||
Once you're done, submit the URL to your working project with all its tests passing.
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,118 @@
|
||||
---
|
||||
id: 587d7faa367417b2b2512bd4
|
||||
title: Add a Hover Effect to a D3 Element
|
||||
challengeType: 6
|
||||
forumTopicId: 301469
|
||||
dashedName: add-a-hover-effect-to-a-d3-element
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
It's possible to add effects that highlight a bar when the user hovers over it with the mouse. So far, the styling for the rectangles is applied with the built-in D3 and SVG methods, but you can use CSS as well.
|
||||
|
||||
You set the CSS class on the SVG elements with the `attr()` method. Then the `:hover` pseudo-class for your new class holds the style rules for any hover effects.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use the `attr()` method to add a class of `bar` to all the `rect` elements. This changes the `fill` color of the bar to brown when you mouse over it.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `rect` elements should have a class of `bar`.
|
||||
|
||||
```js
|
||||
assert($('rect').attr('class') == 'bar');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar:hover {
|
||||
fill: brown;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
.attr("fill", "navy")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (3 * d) - 3);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar:hover {
|
||||
fill: brown;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
.attr("fill", "navy")
|
||||
// Add your code below this line
|
||||
.attr('class', 'bar')
|
||||
// Add your code above this line
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (3 * d) - 3);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,175 @@
|
||||
---
|
||||
id: 587d7faa367417b2b2512bd6
|
||||
title: Add a Tooltip to a D3 Element
|
||||
challengeType: 6
|
||||
forumTopicId: 301470
|
||||
dashedName: add-a-tooltip-to-a-d3-element
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A tooltip shows more information about an item on a page when the user hovers over that item. There are several ways to add a tooltip to a visualization, this challenge uses the SVG `title` element.
|
||||
|
||||
`title` pairs with the `text()` method to dynamically add data to the bars.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Append a `title` element under each `rect` node. Then call the `text()` method with a callback function so the text displays the data value.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should have 9 `title` elements.
|
||||
|
||||
```js
|
||||
assert($('title').length == 9);
|
||||
```
|
||||
|
||||
The first `title` element should have tooltip text of 12.
|
||||
|
||||
```js
|
||||
assert($('title').eq(0).text() == '12');
|
||||
```
|
||||
|
||||
The second `title` element should have tooltip text of 31.
|
||||
|
||||
```js
|
||||
assert($('title').eq(1).text() == '31');
|
||||
```
|
||||
|
||||
The third `title` element should have tooltip text of 22.
|
||||
|
||||
```js
|
||||
assert($('title').eq(2).text() == '22');
|
||||
```
|
||||
|
||||
The fourth `title` element should have tooltip text of 17.
|
||||
|
||||
```js
|
||||
assert($('title').eq(3).text() == '17');
|
||||
```
|
||||
|
||||
The fifth `title` element should have tooltip text of 25.
|
||||
|
||||
```js
|
||||
assert($('title').eq(4).text() == '25');
|
||||
```
|
||||
|
||||
The sixth `title` element should have tooltip text of 18.
|
||||
|
||||
```js
|
||||
assert($('title').eq(5).text() == '18');
|
||||
```
|
||||
|
||||
The seventh `title` element should have tooltip text of 29.
|
||||
|
||||
```js
|
||||
assert($('title').eq(6).text() == '29');
|
||||
```
|
||||
|
||||
The eighth `title` element should have tooltip text of 14.
|
||||
|
||||
```js
|
||||
assert($('title').eq(7).text() == '14');
|
||||
```
|
||||
|
||||
The ninth `title` element should have tooltip text of 9.
|
||||
|
||||
```js
|
||||
assert($('title').eq(8).text() == '9');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar:hover {
|
||||
fill: brown;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => d * 3)
|
||||
.attr("fill", "navy")
|
||||
.attr("class", "bar")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (d * 3 + 3))
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar:hover {
|
||||
fill: brown;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => d * 3)
|
||||
.attr("fill", "navy")
|
||||
.attr("class", "bar")
|
||||
.append("title")
|
||||
.text((d) => d)
|
||||
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (d * 3 + 3))
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,211 @@
|
||||
---
|
||||
id: 587d7fab367417b2b2512bd8
|
||||
title: Add Attributes to the Circle Elements
|
||||
challengeType: 6
|
||||
forumTopicId: 301471
|
||||
dashedName: add-attributes-to-the-circle-elements
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last challenge created the `circle` elements for each point in the `dataset`, and appended them to the SVG canvas. But D3 needs more information about the position and size of each `circle` to display them correctly.
|
||||
|
||||
A `circle` in SVG has three main attributes. The `cx` and `cy` attributes are the coordinates. They tell D3 where to position the *center* of the shape on the SVG canvas. The radius (`r` attribute) gives the size of the `circle`.
|
||||
|
||||
Just like the `rect` `y` coordinate, the `cy` attribute for a `circle` is measured from the top of the SVG canvas, not from the bottom.
|
||||
|
||||
All three attributes can use a callback function to set their values dynamically. Remember that all methods chained after `data(dataset)` run once per item in `dataset`. The `d` parameter in the callback function refers to the current item in `dataset`, which is an array for each point. You use bracket notation, like `d[0]`, to access the values in that array.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add `cx`, `cy`, and `r` attributes to the `circle` elements. The `cx` value should be the first number in the array for each item in `dataset`. The `cy` value should be based off the second number in the array, but make sure to show the chart right-side-up and not inverted. The `r` value should be 5 for all circles.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should have 10 `circle` elements.
|
||||
|
||||
```js
|
||||
assert($('circle').length == 10);
|
||||
```
|
||||
|
||||
The first `circle` element should have a `cx` value of 34, a `cy` value of 422, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(0).attr('cx') == '34' &&
|
||||
$('circle').eq(0).attr('cy') == '422' &&
|
||||
$('circle').eq(0).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The second `circle` element should have a `cx` value of 109, a `cy` value of 220, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(1).attr('cx') == '109' &&
|
||||
$('circle').eq(1).attr('cy') == '220' &&
|
||||
$('circle').eq(1).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The third `circle` element should have a `cx` value of 310, a `cy` value of 380, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(2).attr('cx') == '310' &&
|
||||
$('circle').eq(2).attr('cy') == '380' &&
|
||||
$('circle').eq(2).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The fourth `circle` element should have a `cx` value of 79, a `cy` value of 89, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(3).attr('cx') == '79' &&
|
||||
$('circle').eq(3).attr('cy') == '89' &&
|
||||
$('circle').eq(3).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The fifth `circle` element should have a `cx` value of 420, a `cy` value of 280, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(4).attr('cx') == '420' &&
|
||||
$('circle').eq(4).attr('cy') == '280' &&
|
||||
$('circle').eq(4).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The sixth `circle` element should have a `cx` value of 233, a `cy` value of 355, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(5).attr('cx') == '233' &&
|
||||
$('circle').eq(5).attr('cy') == '355' &&
|
||||
$('circle').eq(5).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The seventh `circle` element should have a `cx` value of 333, a `cy` value of 404, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(6).attr('cx') == '333' &&
|
||||
$('circle').eq(6).attr('cy') == '404' &&
|
||||
$('circle').eq(6).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The eighth `circle` element should have a `cx` value of 222, a `cy` value of 167, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(7).attr('cx') == '222' &&
|
||||
$('circle').eq(7).attr('cy') == '167' &&
|
||||
$('circle').eq(7).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The ninth `circle` element should have a `cx` value of 78, a `cy` value of 180, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(8).attr('cx') == '78' &&
|
||||
$('circle').eq(8).attr('cy') == '180' &&
|
||||
$('circle').eq(8).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The tenth `circle` element should have a `cx` value of 21, a `cy` value of 377, and an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('circle').eq(9).attr('cx') == '21' &&
|
||||
$('circle').eq(9).attr('cy') == '377' &&
|
||||
$('circle').eq(9).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d) => d[0])
|
||||
.attr("cy", (d) => h - d[1])
|
||||
.attr("r", 5)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,198 @@
|
||||
---
|
||||
id: 587d7fad367417b2b2512bdf
|
||||
title: Add Axes to a Visualization
|
||||
challengeType: 6
|
||||
forumTopicId: 301472
|
||||
dashedName: add-axes-to-a-visualization
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another way to improve the scatter plot is to add an x-axis and a y-axis.
|
||||
|
||||
D3 has two methods, `axisLeft()` and `axisBottom()`, to render the y-axis and x-axis, respectively. Here's an example to create the x-axis based on the `xScale` in the previous challenges:
|
||||
|
||||
```js
|
||||
const xAxis = d3.axisBottom(xScale);
|
||||
```
|
||||
|
||||
The next step is to render the axis on the SVG canvas. To do so, you can use a general SVG component, the `g` element. The `g` stands for group. Unlike `rect`, `circle`, and `text`, an axis is just a straight line when it's rendered. Because it is a simple shape, using `g` works. The last step is to apply a `transform` attribute to position the axis on the SVG canvas in the right place. Otherwise, the line would render along the border of SVG canvas and wouldn't be visible. SVG supports different types of `transforms`, but positioning an axis needs `translate`. When it's applied to the `g` element, it moves the whole group over and down by the given amounts. Here's an example:
|
||||
|
||||
```js
|
||||
const xAxis = d3.axisBottom(xScale);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", "translate(0, " + (h - padding) + ")")
|
||||
.call(xAxis);
|
||||
```
|
||||
|
||||
The above code places the x-axis at the bottom of the SVG canvas. Then it's passed as an argument to the `call()` method. The y-axis works in the same way, except the `translate` argument is in the form (x, 0). Because `translate` is a string in the `attr()` method above, you can use concatenation to include variable values for its arguments.
|
||||
|
||||
# --instructions--
|
||||
|
||||
The scatter plot now has an x-axis. Create a y-axis in a variable named `yAxis` using the `axisLeft()` method. Then render the axis using a `g` element. Make sure to use a `transform` attribute to translate the axis by the amount of padding units right, and 0 units down. Remember to `call()` the axis.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use the `axisLeft()` method with `yScale` passed as the argument.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.axisLeft\(yScale\)/g));
|
||||
```
|
||||
|
||||
The y-axis `g` element should have a `transform` attribute to translate the axis by (60, 0).
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('g')
|
||||
.eq(10)
|
||||
.attr('transform')
|
||||
.match(/translate\(60\s*?,\s*?0\)/g)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should call the `yAxis`.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.call\(\s*yAxis\s*\)/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
const padding = 60;
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[1])])
|
||||
.range([h - padding, padding]);
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d) => xScale(d[0]))
|
||||
.attr("cy",(d) => yScale(d[1]))
|
||||
.attr("r", (d) => 5);
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => (d[0] + "," + d[1]))
|
||||
.attr("x", (d) => xScale(d[0] + 10))
|
||||
.attr("y", (d) => yScale(d[1]))
|
||||
|
||||
const xAxis = d3.axisBottom(xScale);
|
||||
// Add your code below this line
|
||||
const yAxis = undefined;
|
||||
// Add your code above this line
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", "translate(0," + (h - padding) + ")")
|
||||
.call(xAxis);
|
||||
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
const padding = 60;
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[1])])
|
||||
.range([h - padding, padding]);
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d) => xScale(d[0]))
|
||||
.attr("cy",(d) => yScale(d[1]))
|
||||
.attr("r", (d) => 5);
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => (d[0] + "," + d[1]))
|
||||
.attr("x", (d) => xScale(d[0] + 10))
|
||||
.attr("y", (d) => yScale(d[1]))
|
||||
|
||||
const xAxis = d3.axisBottom(xScale);
|
||||
|
||||
const yAxis = d3.axisLeft(yScale);
|
||||
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", "translate(0," + (h - padding) + ")")
|
||||
.call(xAxis);
|
||||
|
||||
svg.append("g")
|
||||
.attr("transform", "translate(" + padding + ",0)")
|
||||
.call(yAxis)
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,91 @@
|
||||
---
|
||||
id: 587d7fa7367417b2b2512bc8
|
||||
title: Add Classes with D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301473
|
||||
dashedName: add-classes-with-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Using a lot of inline styles on HTML elements gets hard to manage, even for smaller apps. It's easier to add a class to elements and style that class one time using CSS rules. D3 has the `attr()` method to add any HTML attribute to an element, including a class name.
|
||||
|
||||
The `attr()` method works the same way that `style()` does. It takes comma-separated values, and can use a callback function. Here's an example to add a class of "container" to a selection:
|
||||
|
||||
`selection.attr("class", "container");`
|
||||
|
||||
Note that the "class" parameter will remain the same whenever you need to add a class and only the "container" parameter will change.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add the `attr()` method to the code in the editor and put a class of `bar` on the `div` elements.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `div` elements should have a class of `bar`.
|
||||
|
||||
```js
|
||||
assert($('div').attr('class') == 'bar');
|
||||
```
|
||||
|
||||
Your code should use the `attr()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.attr/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
// Add your code below this line
|
||||
.attr("class","bar");
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,103 @@
|
||||
---
|
||||
id: 587d7fa6367417b2b2512bc2
|
||||
title: Add Document Elements with D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301474
|
||||
dashedName: add-document-elements-with-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 has several methods that let you add and change elements in your document.
|
||||
|
||||
The `select()` method selects one element from the document. It takes an argument for the name of the element you want and returns an HTML node for the first element in the document that matches the name. Here's an example:
|
||||
|
||||
`const anchor = d3.select("a");`
|
||||
|
||||
The above example finds the first anchor tag on the page and saves an HTML node for it in the variable `anchor`. You can use the selection with other methods. The "d3" part of the example is a reference to the D3 object, which is how you access D3 methods.
|
||||
|
||||
Two other useful methods are `append()` and `text()`.
|
||||
|
||||
The `append()` method takes an argument for the element you want to add to the document. It appends an HTML node to a selected item, and returns a handle to that node.
|
||||
|
||||
The `text()` method either sets the text of the selected node, or gets the current text. To set the value, you pass a string as an argument inside the parentheses of the method.
|
||||
|
||||
Here's an example that selects an unordered list, appends a list item, and adds text:
|
||||
|
||||
```js
|
||||
d3.select("ul")
|
||||
.append("li")
|
||||
.text("Very important item");
|
||||
```
|
||||
|
||||
D3 allows you to chain several methods together with periods to perform a number of actions in a row.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use the `select` method to select the `body` tag in the document. Then `append` an `h1` tag to it, and add the text "Learning D3" into the `h1` element.
|
||||
|
||||
# --hints--
|
||||
|
||||
The `body` should have one `h1` element.
|
||||
|
||||
```js
|
||||
assert($('body').children('h1').length == 1);
|
||||
```
|
||||
|
||||
The `h1` element should have the text "Learning D3" in it.
|
||||
|
||||
```js
|
||||
assert($('h1').text() == 'Learning D3');
|
||||
```
|
||||
|
||||
Your code should access the `d3` object.
|
||||
|
||||
```js
|
||||
assert(code.match(/d3/g));
|
||||
```
|
||||
|
||||
Your code should use the `select` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.select/g));
|
||||
```
|
||||
|
||||
Your code should use the `append` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.append/g));
|
||||
```
|
||||
|
||||
Your code should use the `text` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.text/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
d3.select("body")
|
||||
.append("h1")
|
||||
.text("Learning D3")
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,74 @@
|
||||
---
|
||||
id: 587d7fa7367417b2b2512bc6
|
||||
title: Add Inline Styling to Elements
|
||||
challengeType: 6
|
||||
forumTopicId: 301475
|
||||
dashedName: add-inline-styling-to-elements
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 lets you add inline CSS styles on dynamic elements with the `style()` method.
|
||||
|
||||
The `style()` method takes a comma-separated key-value pair as an argument. Here's an example to set the selection's text color to blue:
|
||||
|
||||
`selection.style("color","blue");`
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add the `style()` method to the code in the editor to make all the displayed text have a `font-family` of `verdana`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `h2` elements should have a `font-family` of verdana.
|
||||
|
||||
```js
|
||||
assert($('h2').css('font-family') == 'verdana');
|
||||
```
|
||||
|
||||
Your code should use the `style()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.style/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text((d) => (d + " USD"))
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text((d) => (d + " USD"))
|
||||
.style("font-family", "verdana")
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,154 @@
|
||||
---
|
||||
id: 587d7faa367417b2b2512bd2
|
||||
title: Add Labels to D3 Elements
|
||||
challengeType: 6
|
||||
forumTopicId: 301476
|
||||
dashedName: add-labels-to-d3-elements
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 lets you label a graph element, such as a bar, using the SVG `text` element.
|
||||
|
||||
Like the `rect` element, a `text` element needs to have `x` and `y` attributes, to place it on the SVG canvas. It also needs to access the data to display those values.
|
||||
|
||||
D3 gives you a high level of control over how you label your bars.
|
||||
|
||||
# --instructions--
|
||||
|
||||
The code in the editor already binds the data to each new `text` element. First, append `text` nodes to the `svg`. Next, add attributes for the `x` and `y` coordinates. They should be calculated the same way as the `rect` ones, except the `y` value for the `text` should make the label sit 3 units higher than the bar. Finally, use the D3 `text()` method to set the label equal to the data point value.
|
||||
|
||||
**Note**
|
||||
For the label to sit higher than the bar, decide if the `y` value for the `text` should be 3 greater or 3 less than the `y` value for the bar.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `text` element should have a label of 12 and a `y` value of 61.
|
||||
|
||||
```js
|
||||
assert($('text').eq(0).text() == '12' && $('text').eq(0).attr('y') == '61');
|
||||
```
|
||||
|
||||
The second `text` element should have a label of 31 and a `y` value of 4.
|
||||
|
||||
```js
|
||||
assert($('text').eq(1).text() == '31' && $('text').eq(1).attr('y') == '4');
|
||||
```
|
||||
|
||||
The third `text` element should have a label of 22 and a `y` value of 31.
|
||||
|
||||
```js
|
||||
assert($('text').eq(2).text() == '22' && $('text').eq(2).attr('y') == '31');
|
||||
```
|
||||
|
||||
The fourth `text` element should have a label of 17 and a `y` value of 46.
|
||||
|
||||
```js
|
||||
assert($('text').eq(3).text() == '17' && $('text').eq(3).attr('y') == '46');
|
||||
```
|
||||
|
||||
The fifth `text` element should have a label of 25 and a `y` value of 22.
|
||||
|
||||
```js
|
||||
assert($('text').eq(4).text() == '25' && $('text').eq(4).attr('y') == '22');
|
||||
```
|
||||
|
||||
The sixth `text` element should have a label of 18 and a `y` value of 43.
|
||||
|
||||
```js
|
||||
assert($('text').eq(5).text() == '18' && $('text').eq(5).attr('y') == '43');
|
||||
```
|
||||
|
||||
The seventh `text` element should have a label of 29 and a `y` value of 10.
|
||||
|
||||
```js
|
||||
assert($('text').eq(6).text() == '29' && $('text').eq(6).attr('y') == '10');
|
||||
```
|
||||
|
||||
The eighth `text` element should have a label of 14 and a `y` value of 55.
|
||||
|
||||
```js
|
||||
assert($('text').eq(7).text() == '14' && $('text').eq(7).attr('y') == '55');
|
||||
```
|
||||
|
||||
The ninth `text` element should have a label of 9 and a `y` value of 70.
|
||||
|
||||
```js
|
||||
assert($('text').eq(8).text() == '9' && $('text').eq(8).attr('y') == '70');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
.attr("fill", "navy");
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
<body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
.attr("fill", "navy");
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (3 * d) - 3)
|
||||
.text((d) => d)
|
||||
</script>
|
||||
<body>
|
||||
```
|
@ -0,0 +1,224 @@
|
||||
---
|
||||
id: 587d7fab367417b2b2512bd9
|
||||
title: Add Labels to Scatter Plot Circles
|
||||
challengeType: 6
|
||||
forumTopicId: 301477
|
||||
dashedName: add-labels-to-scatter-plot-circles
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can add text to create labels for the points in a scatter plot.
|
||||
|
||||
The goal is to display the comma-separated values for the first (`x`) and second (`y`) fields of each item in `dataset`.
|
||||
|
||||
The `text` nodes need `x` and `y` attributes to position it on the SVG canvas. In this challenge, the `y` value (which determines height) can use the same value that the `circle` uses for its `cy` attribute. The `x` value can be slightly larger than the `cx` value of the `circle`, so the label is visible. This will push the label to the right of the plotted point.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Label each point on the scatter plot using the `text` elements. The text of the label should be the two values separated by a comma and a space. For example, the label for the first point is "34, 78". Set the `x` attribute so it's 5 units more than the value you used for the `cx` attribute on the `circle`. Set the `y` attribute the same way that's used for the `cy` value on the `circle`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should have 10 `text` elements.
|
||||
|
||||
```js
|
||||
assert($('text').length == 10);
|
||||
```
|
||||
|
||||
The first label should have text of "34, 78", an `x` value of 39, and a `y` value of 422.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(0).text() == '34, 78' &&
|
||||
$('text').eq(0).attr('x') == '39' &&
|
||||
$('text').eq(0).attr('y') == '422'
|
||||
);
|
||||
```
|
||||
|
||||
The second label should have text of "109, 280", an `x` value of 114, and a `y` value of 220.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(1).text() == '109, 280' &&
|
||||
$('text').eq(1).attr('x') == '114' &&
|
||||
$('text').eq(1).attr('y') == '220'
|
||||
);
|
||||
```
|
||||
|
||||
The third label should have text of "310, 120", an `x` value of 315, and a `y` value of 380.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(2).text() == '310, 120' &&
|
||||
$('text').eq(2).attr('x') == '315' &&
|
||||
$('text').eq(2).attr('y') == '380'
|
||||
);
|
||||
```
|
||||
|
||||
The fourth label should have text of "79, 411", an `x` value of 84, and a `y` value of 89.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(3).text() == '79, 411' &&
|
||||
$('text').eq(3).attr('x') == '84' &&
|
||||
$('text').eq(3).attr('y') == '89'
|
||||
);
|
||||
```
|
||||
|
||||
The fifth label should have text of "420, 220", an `x` value of 425, and a `y` value of 280.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(4).text() == '420, 220' &&
|
||||
$('text').eq(4).attr('x') == '425' &&
|
||||
$('text').eq(4).attr('y') == '280'
|
||||
);
|
||||
```
|
||||
|
||||
The sixth label should have text of "233, 145", an `x` value of 238, and a `y` value of 355.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(5).text() == '233, 145' &&
|
||||
$('text').eq(5).attr('x') == '238' &&
|
||||
$('text').eq(5).attr('y') == '355'
|
||||
);
|
||||
```
|
||||
|
||||
The seventh label should have text of "333, 96", an `x` value of 338, and a `y` value of 404.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(6).text() == '333, 96' &&
|
||||
$('text').eq(6).attr('x') == '338' &&
|
||||
$('text').eq(6).attr('y') == '404'
|
||||
);
|
||||
```
|
||||
|
||||
The eighth label should have text of "222, 333", an `x` value of 227, and a `y` value of 167.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(7).text() == '222, 333' &&
|
||||
$('text').eq(7).attr('x') == '227' &&
|
||||
$('text').eq(7).attr('y') == '167'
|
||||
);
|
||||
```
|
||||
|
||||
The ninth label should have text of "78, 320", an `x` value of 83, and a `y` value of 180.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(8).text() == '78, 320' &&
|
||||
$('text').eq(8).attr('x') == '83' &&
|
||||
$('text').eq(8).attr('y') == '180'
|
||||
);
|
||||
```
|
||||
|
||||
The tenth label should have text of "21, 123", an `x` value of 26, and a `y` value of 377.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('text').eq(9).text() == '21, 123' &&
|
||||
$('text').eq(9).attr('x') == '26' &&
|
||||
$('text').eq(9).attr('y') == '377'
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d, i) => d[0])
|
||||
.attr("cy", (d, i) => h - d[1])
|
||||
.attr("r", 5);
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d, i) => d[0])
|
||||
.attr("cy", (d, i) => h - d[1])
|
||||
.attr("r", 5);
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.attr("x", (d) => d[0] + 5)
|
||||
.attr("y", (d) => h - d[1])
|
||||
.text((d) => (d[0] + ", " + d[1]))
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,124 @@
|
||||
---
|
||||
id: 587d7fa7367417b2b2512bc7
|
||||
title: Change Styles Based on Data
|
||||
challengeType: 6
|
||||
forumTopicId: 301479
|
||||
dashedName: change-styles-based-on-data
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 is about visualization and presentation of data. It's likely you'll want to change the styling of elements based on the data. You can use a callback function in the `style()` method to change the styling for different elements.
|
||||
|
||||
For example, you may want to color a data point blue if it has a value less than 20, and red otherwise. You can use a callback function in the `style()` method and include the conditional logic. The callback function uses the `d` parameter to represent the data point:
|
||||
|
||||
```js
|
||||
selection.style("color", (d) => {
|
||||
/* Logic that returns the color based on a condition */
|
||||
});
|
||||
```
|
||||
|
||||
The `style()` method is not limited to setting the `color` - it can be used with other CSS properties as well.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add the `style()` method to the code in the editor to set the `color` of the `h2` elements conditionally. Write the callback function so if the data value is less than 20, it returns "red", otherwise it returns "green".
|
||||
|
||||
**Note**
|
||||
You can use if-else logic, or the ternary operator.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `h2` should have a `color` of red.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(0).css('color') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
The second `h2` should have a `color` of green.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(1).css('color') == 'rgb(0, 128, 0)');
|
||||
```
|
||||
|
||||
The third `h2` should have a `color` of green.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(2).css('color') == 'rgb(0, 128, 0)');
|
||||
```
|
||||
|
||||
The fourth `h2` should have a `color` of red.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(3).css('color') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
The fifth `h2` should have a `color` of green.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(4).css('color') == 'rgb(0, 128, 0)');
|
||||
```
|
||||
|
||||
The sixth `h2` should have a `color` of red.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(5).css('color') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
The seventh `h2` should have a `color` of green.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(6).css('color') == 'rgb(0, 128, 0)');
|
||||
```
|
||||
|
||||
The eighth `h2` should have a `color` of red.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(7).css('color') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
The ninth `h2` should have a `color` of red.
|
||||
|
||||
```js
|
||||
assert($('h2').eq(8).css('color') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text((d) => (d + " USD"))
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text((d) => (d + " USD"))
|
||||
.style("color", (d) => d < 20 ? "red" : "green")
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,88 @@
|
||||
---
|
||||
id: 587d7fa9367417b2b2512bd1
|
||||
title: Change the Color of an SVG Element
|
||||
challengeType: 6
|
||||
forumTopicId: 301480
|
||||
dashedName: change-the-color-of-an-svg-element
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The bars are in the right position, but they are all the same black color. SVG has a way to change the color of the bars.
|
||||
|
||||
In SVG, a `rect` shape is colored with the `fill` attribute. It supports hex codes, color names, and rgb values, as well as more complex options like gradients and transparency.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add an `attr()` method to set the "fill" of all the bars to the color "navy".
|
||||
|
||||
# --hints--
|
||||
|
||||
The bars should all have a `fill` color of navy.
|
||||
|
||||
```js
|
||||
assert($('rect').css('fill') == 'rgb(0, 0, 128)');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d)
|
||||
.attr("fill", "navy");
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,162 @@
|
||||
---
|
||||
id: 587d7fa8367417b2b2512bca
|
||||
title: Change the Presentation of a Bar Chart
|
||||
challengeType: 6
|
||||
forumTopicId: 301481
|
||||
dashedName: change-the-presentation-of-a-bar-chart
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last challenge created a bar chart, but there are a couple of formatting changes that could improve it:
|
||||
|
||||
1) Add space between each bar to visually separate them, which is done by adding a margin to the CSS for the `bar` class
|
||||
|
||||
2) Increase the height of the bars to better show the difference in values, which is done by multiplying the value by a number to scale the height
|
||||
|
||||
# --instructions--
|
||||
|
||||
First, add a `margin` of 2px to the `bar` class in the `style` tag. Next, change the callback function in the `style()` method so it returns a value 10 times the original data value (plus the "px").
|
||||
|
||||
**Note**
|
||||
Multiplying each data point by the *same* constant only alters the scale. It's like zooming in, and it doesn't change the meaning of the underlying data.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `div` should have a `height` of 120 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(0).css('height') == '120px' &&
|
||||
$('div').eq(0).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The second `div` should have a `height` of 310 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(1).css('height') == '310px' &&
|
||||
$('div').eq(1).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The third `div` should have a `height` of 220 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(2).css('height') == '220px' &&
|
||||
$('div').eq(2).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The fourth `div` should have a `height` of 170 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(3).css('height') == '170px' &&
|
||||
$('div').eq(3).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The fifth `div` should have a `height` of 250 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(4).css('height') == '250px' &&
|
||||
$('div').eq(4).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The sixth `div` should have a `height` of 180 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(5).css('height') == '180px' &&
|
||||
$('div').eq(5).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The seventh `div` should have a `height` of 290 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(6).css('height') == '290px' &&
|
||||
$('div').eq(6).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The eighth `div` should have a `height` of 140 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(7).css('height') == '140px' &&
|
||||
$('div').eq(7).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
The ninth `div` should have a `height` of 90 pixels and a `margin` of 2 pixels.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('div').eq(8).css('height') == '90px' &&
|
||||
$('div').eq(8).css('margin-right') == '2px'
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
/* Only change code below this line */
|
||||
|
||||
|
||||
/* Only change code above this line */
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
.attr("class", "bar")
|
||||
.style("height", (d) => (d + "px"))
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
margin: 2px;
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
.attr("class", "bar")
|
||||
.style("height", (d) => (d * 10 + "px"))
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,110 @@
|
||||
---
|
||||
id: 587d7fa8367417b2b2512bcd
|
||||
title: Create a Bar for Each Data Point in the Set
|
||||
challengeType: 6
|
||||
forumTopicId: 301482
|
||||
dashedName: create-a-bar-for-each-data-point-in-the-set
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last challenge added only one rectangle to the `svg` element to represent a bar. Here, you'll combine what you've learned so far about `data()`, `enter()`, and SVG shapes to create and append a rectangle for each data point in `dataset`.
|
||||
|
||||
A previous challenge showed the format for how to create and append a `div` for each item in `dataset`:
|
||||
|
||||
```js
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
```
|
||||
|
||||
There are a few differences working with `rect` elements instead of `divs`. The `rects` must be appended to an `svg` element, not directly to the `body`. Also, you need to tell D3 where to place each `rect` within the `svg` area. The bar placement will be covered in the next challenge.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use the `data()`, `enter()`, and `append()` methods to create and append a `rect` for each item in `dataset`. The bars should display all on top of each other; this will be fixed in the next challenge.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your document should have 9 `rect` elements.
|
||||
|
||||
```js
|
||||
assert($('rect').length == 9);
|
||||
```
|
||||
|
||||
Your code should use the `data()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.data/g));
|
||||
```
|
||||
|
||||
Your code should use the `enter()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.enter/g));
|
||||
```
|
||||
|
||||
Your code should use the `append()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.append/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
.attr("x", 0)
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", 100);
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", 0)
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", 100);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,86 @@
|
||||
---
|
||||
id: 587d7fab367417b2b2512bda
|
||||
title: Create a Linear Scale with D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301483
|
||||
dashedName: create-a-linear-scale-with-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The bar and scatter plot charts both plotted data directly onto the SVG canvas. However, if the height of a bar or one of the data points were larger than the SVG height or width values, it would go outside the SVG area.
|
||||
|
||||
In D3, there are scales to help plot data. `Scales` are functions that tell the program how to map a set of raw data points onto the pixels of the SVG canvas.
|
||||
|
||||
For example, say you have a 100x500-sized SVG canvas and you want to plot Gross Domestic Product (GDP) for a number of countries. The set of numbers would be in the billion or trillion-dollar range. You provide D3 a type of scale to tell it how to place the large GDP values into that 100x500-sized area.
|
||||
|
||||
It's unlikely you would plot raw data as-is. Before plotting it, you set the scale for your entire data set, so that the `x` and `y` values fit your canvas width and height.
|
||||
|
||||
D3 has several scale types. For a linear scale (usually used with quantitative data), there is the D3 method `scaleLinear()`:
|
||||
|
||||
`const scale = d3.scaleLinear()`
|
||||
|
||||
By default, a scale uses the identity relationship. The value of the input is the same as the value of the output. A separate challenge covers how to change this.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Change the `scale` variable to create a linear scale. Then set the `output` variable to the scale called with an input argument of 50.
|
||||
|
||||
# --hints--
|
||||
|
||||
The text in the `h2` should be 50.
|
||||
|
||||
```js
|
||||
assert($('h2').text() == '50');
|
||||
```
|
||||
|
||||
Your code should use the `scaleLinear()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.scaleLinear/g));
|
||||
```
|
||||
|
||||
The `output` variable should call `scale` with an argument of 50.
|
||||
|
||||
```js
|
||||
assert(output == 50 && code.match(/scale\(\s*?50\s*?\)/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
// Add your code below this line
|
||||
|
||||
const scale = undefined; // Create the scale here
|
||||
const output = scale(); // Call scale with an argument here
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
|
||||
const scale = d3.scaleLinear();
|
||||
const output = scale(50);
|
||||
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,104 @@
|
||||
---
|
||||
id: 587d7fab367417b2b2512bd7
|
||||
title: Create a Scatterplot with SVG Circles
|
||||
challengeType: 6
|
||||
forumTopicId: 301484
|
||||
dashedName: create-a-scatterplot-with-svg-circles
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
A scatter plot is another type of visualization. It usually uses circles to map data points, which have two values each. These values tie to the `x` and `y` axes, and are used to position the circle in the visualization.
|
||||
|
||||
SVG has a `circle` tag to create the circle shape. It works a lot like the `rect` elements you used for the bar chart.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use the `data()`, `enter()`, and `append()` methods to bind `dataset` to new `circle` elements that are appended to the SVG canvas.
|
||||
|
||||
**Note**
|
||||
The circles won't be visible because we haven't set their attributes yet. We'll do that in the next challenge.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should have 10 `circle` elements.
|
||||
|
||||
```js
|
||||
assert($('circle').length == 10);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,103 @@
|
||||
---
|
||||
id: 587d7fa8367417b2b2512bcc
|
||||
title: Display Shapes with SVG
|
||||
challengeType: 6
|
||||
forumTopicId: 301485
|
||||
dashedName: display-shapes-with-svg
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last challenge created an `svg` element with a given width and height, which was visible because it had a `background-color` applied to it in the `style` tag. The code made space for the given width and height.
|
||||
|
||||
The next step is to create a shape to put in the `svg` area. There are a number of supported shapes in SVG, such as rectangles and circles. They are used to display data. For example, a rectangle (`<rect>`) SVG shape could create a bar in a bar chart.
|
||||
|
||||
When you place a shape into the `svg` area, you can specify where it goes with `x` and `y` coordinates. The origin point of (0, 0) is in the upper-left corner. Positive values for `x` push the shape to the right, and positive values for `y` push the shape down from the origin point.
|
||||
|
||||
To place a shape in the middle of the 500 (width) x 100 (height) `svg` from last challenge, the `x` coordinate would be 250 and the `y` coordinate would be 50.
|
||||
|
||||
An SVG `rect` has four attributes. There are the `x` and `y` coordinates for where it is placed in the `svg` area. It also has a `height` and `width` to specify the size.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add a `rect` shape to the `svg` using `append()`, and give it a `width` attribute of 25 and `height` attribute of 100. Also, give the `rect` `x` and `y` attributes each set to 0.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your document should have 1 `rect` element.
|
||||
|
||||
```js
|
||||
assert($('rect').length == 1);
|
||||
```
|
||||
|
||||
The `rect` element should have a `width` attribute set to 25.
|
||||
|
||||
```js
|
||||
assert($('rect').attr('width') == '25');
|
||||
```
|
||||
|
||||
The `rect` element should have a `height` attribute set to 100.
|
||||
|
||||
```js
|
||||
assert($('rect').attr('height') == '100');
|
||||
```
|
||||
|
||||
The `rect` element should have an `x` attribute set to 0.
|
||||
|
||||
```js
|
||||
assert($('rect').attr('x') == '0');
|
||||
```
|
||||
|
||||
The `rect` element should have a `y` attribute set to 0.
|
||||
|
||||
```js
|
||||
assert($('rect').attr('y') == '0');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
.append("rect")
|
||||
.attr("width", 25)
|
||||
.attr("height", 100)
|
||||
.attr("x", 0)
|
||||
.attr("y", 0);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,147 @@
|
||||
---
|
||||
id: 587d7fa9367417b2b2512bcf
|
||||
title: Dynamically Change the Height of Each Bar
|
||||
challengeType: 6
|
||||
forumTopicId: 301486
|
||||
dashedName: dynamically-change-the-height-of-each-bar
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The height of each bar can be set to the value of the data point in the array, similar to how the `x` value was set dynamically.
|
||||
|
||||
```js
|
||||
selection.attr("property", (d, i) => {
|
||||
/*
|
||||
* d is the data point value
|
||||
* i is the index of the data point in the array
|
||||
*/
|
||||
})
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Change the callback function for the `height` attribute to return the data value times 3.
|
||||
|
||||
**Note**
|
||||
Remember that multiplying all data points by the same constant scales the data (like zooming in). It helps to see the differences between bar values in this example.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `rect` should have a `height` of 36.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(0).attr('height') == '36');
|
||||
```
|
||||
|
||||
The second `rect` should have a `height` of 93.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(1).attr('height') == '93');
|
||||
```
|
||||
|
||||
The third `rect` should have a `height` of 66.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(2).attr('height') == '66');
|
||||
```
|
||||
|
||||
The fourth `rect` should have a `height` of 51.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(3).attr('height') == '51');
|
||||
```
|
||||
|
||||
The fifth `rect` should have a `height` of 75.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(4).attr('height') == '75');
|
||||
```
|
||||
|
||||
The sixth `rect` should have a `height` of 54.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(5).attr('height') == '54');
|
||||
```
|
||||
|
||||
The seventh `rect` should have a `height` of 87.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(6).attr('height') == '87');
|
||||
```
|
||||
|
||||
The eighth `rect` should have a `height` of 42.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(7).attr('height') == '42');
|
||||
```
|
||||
|
||||
The ninth `rect` should have a `height` of 27.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(8).attr('height') == '27');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => {
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => {
|
||||
return d * 3
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,155 @@
|
||||
---
|
||||
id: 587d7fa9367417b2b2512bce
|
||||
title: Dynamically Set the Coordinates for Each Bar
|
||||
challengeType: 6
|
||||
forumTopicId: 301487
|
||||
dashedName: dynamically-set-the-coordinates-for-each-bar
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last challenge created and appended a rectangle to the `svg` element for each point in `dataset` to represent a bar. Unfortunately, they were all stacked on top of each other.
|
||||
|
||||
The placement of a rectangle is handled by the `x` and `y` attributes. They tell D3 where to start drawing the shape in the `svg` area. The last challenge set them each to 0, so every bar was placed in the upper-left corner.
|
||||
|
||||
For a bar chart, all of the bars should sit on the same vertical level, which means the `y` value stays the same (at 0) for all bars. The `x` value, however, needs to change as you add new bars. Remember that larger `x` values push items farther to the right. As you go through the array elements in `dataset`, the x value should increase.
|
||||
|
||||
The `attr()` method in D3 accepts a callback function to dynamically set that attribute. The callback function takes two arguments, one for the data point itself (usually `d`) and one for the index of the data point in the array. The second argument for the index is optional. Here's the format:
|
||||
|
||||
```js
|
||||
selection.attr("property", (d, i) => {
|
||||
/*
|
||||
* d is the data point value
|
||||
* i is the index of the data point in the array
|
||||
*/
|
||||
})
|
||||
```
|
||||
|
||||
It's important to note that you do NOT need to write a `for` loop or use `forEach()` to iterate over the items in the data set. Recall that the `data()` method parses the data set, and any method that's chained after `data()` is run once for each item in the data set.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Change the `x` attribute callback function so it returns the index times 30.
|
||||
|
||||
**Note**
|
||||
Each bar has a width of 25, so increasing each `x` value by 30 adds some space between the bars. Any value greater than 25 would work in this example.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `rect` should have an `x` value of 0.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(0).attr('x') == '0');
|
||||
```
|
||||
|
||||
The second `rect` should have an `x` value of 30.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(1).attr('x') == '30');
|
||||
```
|
||||
|
||||
The third `rect` should have an `x` value of 60.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(2).attr('x') == '60');
|
||||
```
|
||||
|
||||
The fourth `rect` should have an `x` value of 90.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(3).attr('x') == '90');
|
||||
```
|
||||
|
||||
The fifth `rect` should have an `x` value of 120.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(4).attr('x') == '120');
|
||||
```
|
||||
|
||||
The sixth `rect` should have an `x` value of 150.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(5).attr('x') == '150');
|
||||
```
|
||||
|
||||
The seventh `rect` should have an `x` value of 180.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(6).attr('x') == '180');
|
||||
```
|
||||
|
||||
The eighth `rect` should have an `x` value of 210.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(7).attr('x') == '210');
|
||||
```
|
||||
|
||||
The ninth `rect` should have an `x` value of 240.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(8).attr('x') == '240');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => {
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
})
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", 100);
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => {
|
||||
return i * 30
|
||||
})
|
||||
.attr("y", 0)
|
||||
.attr("width", 25)
|
||||
.attr("height", 100);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,144 @@
|
||||
---
|
||||
id: 587d7fa9367417b2b2512bd0
|
||||
title: Invert SVG Elements
|
||||
challengeType: 6
|
||||
forumTopicId: 301488
|
||||
dashedName: invert-svg-elements
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You may have noticed the bar chart looked like it's upside-down, or inverted. This is because of how SVG uses (x, y) coordinates.
|
||||
|
||||
In SVG, the origin point for the coordinates is in the upper-left corner. An `x` coordinate of 0 places a shape on the left edge of the SVG area. A `y` coordinate of 0 places a shape on the top edge of the SVG area. Higher `x` values push the rectangle to the right. Higher `y` values push the rectangle down.
|
||||
|
||||
To make the bars right-side-up, you need to change the way the `y` coordinate is calculated. It needs to account for both the height of the bar and the total height of the SVG area.
|
||||
|
||||
The height of the SVG area is 100. If you have a data point of 0 in the set, you would want the bar to start at the bottom of the SVG area (not the top). To do this, the `y` coordinate needs a value of 100. If the data point value were 1, you would start with a `y` coordinate of 100 to set the bar at the bottom. Then you need to account for the height of the bar of 1, so the final `y` coordinate would be 99.
|
||||
|
||||
The `y` coordinate that is `y = heightOfSVG - heightOfBar` would place the bars right-side-up.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Change the callback function for the `y` attribute to set the bars right-side-up. Remember that the `height` of the bar is 3 times the data value `d`.
|
||||
|
||||
**Note**
|
||||
In general, the relationship is `y = h - m * d`, where `m` is the constant that scales the data points.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `rect` should have a `y` value of 64.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(0).attr('y') == h - dataset[0] * 3);
|
||||
```
|
||||
|
||||
The second `rect` should have a `y` value of 7.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(1).attr('y') == h - dataset[1] * 3);
|
||||
```
|
||||
|
||||
The third `rect` should have a `y` value of 34.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(2).attr('y') == h - dataset[2] * 3);
|
||||
```
|
||||
|
||||
The fourth `rect` should have a `y` value of 49.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(3).attr('y') == h - dataset[3] * 3);
|
||||
```
|
||||
|
||||
The fifth `rect` should have a `y` value of 25.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(4).attr('y') == h - dataset[4] * 3);
|
||||
```
|
||||
|
||||
The sixth `rect` should have a `y` value of 46.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(5).attr('y') == h - dataset[5] * 3);
|
||||
```
|
||||
|
||||
The seventh `rect` should have a `y` value of 13.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(6).attr('y') == h - dataset[6] * 3);
|
||||
```
|
||||
|
||||
The eighth `rect` should have a `y` value of 58.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(7).attr('y') == h - dataset[7] * 3);
|
||||
```
|
||||
|
||||
The ninth `rect` should have a `y` value of 73.
|
||||
|
||||
```js
|
||||
assert($('rect').eq(8).attr('y') == h - dataset[8] * 3);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => {
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
})
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d);
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => 3 * d);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,94 @@
|
||||
---
|
||||
id: 587d7fa8367417b2b2512bcb
|
||||
title: Learn About SVG in D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301489
|
||||
dashedName: learn-about-svg-in-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
<dfn>SVG</dfn> stands for <dfn>Scalable Vector Graphics</dfn>.
|
||||
|
||||
Here "scalable" means that, if you zoom in or out on an object, it would not appear pixelated. It scales with the display system, whether it's on a small mobile screen or a large TV monitor.
|
||||
|
||||
SVG is used to make common geometric shapes. Since D3 maps data into a visual representation, it uses SVG to create the shapes for the visualization. SVG shapes for a web page must go within an HTML `svg` tag.
|
||||
|
||||
CSS can be scalable when styles use relative units (such as `vh`, `vw`, or percentages), but using SVG is more flexible to build data visualizations.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add an `svg` node to the `body` using `append()`. Give it a `width` attribute set to the provided `w` constant and a `height` attribute set to the provided `h` constant using the `attr()` or `style()` methods for each. You'll see it in the output because there's a `background-color` of pink applied to it in the `style` tag.
|
||||
|
||||
**Note**
|
||||
When using `attr()` width and height attributes do not have units. This is the building block of scaling - the element will always have a 5:1 width to height ratio, no matter what the zoom level is.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your document should have 1 `svg` element.
|
||||
|
||||
```js
|
||||
assert($('svg').length == 1);
|
||||
```
|
||||
|
||||
The `svg` element should have a `width` attribute set to 500 or styled to have a width of 500px.
|
||||
|
||||
```js
|
||||
assert($('svg').attr('width') == '500' || $('svg').css('width') == '500px');
|
||||
```
|
||||
|
||||
The `svg` element should have a `height` attribute set to 100 or styled to have a height of 100px.
|
||||
|
||||
```js
|
||||
assert($('svg').attr('height') == '100' || $('svg').css('height') == '100px');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
svg {
|
||||
background-color: pink;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
svg {
|
||||
background-color: pink;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h)
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,80 @@
|
||||
---
|
||||
id: 587d7fa6367417b2b2512bc3
|
||||
title: Select a Group of Elements with D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301490
|
||||
dashedName: select-a-group-of-elements-with-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 also has the `selectAll()` method to select a group of elements. It returns an array of HTML nodes for all the items in the document that match the input string. Here's an example to select all the anchor tags in a document:
|
||||
|
||||
`const anchors = d3.selectAll("a");`
|
||||
|
||||
Like the `select()` method, `selectAll()` supports method chaining, and you can use it with other methods.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Select all of the `li` tags in the document, and change their text to "list item" by chaining the `.text()` method.
|
||||
|
||||
# --hints--
|
||||
|
||||
There should be 3 `li` elements on the page, and the text in each one should say "list item". Capitalization and spacing should match exactly.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('li')
|
||||
.text()
|
||||
.match(/list item/g).length == 3
|
||||
);
|
||||
```
|
||||
|
||||
Your code should access the `d3` object.
|
||||
|
||||
```js
|
||||
assert(code.match(/d3/g));
|
||||
```
|
||||
|
||||
Your code should use the `selectAll` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.selectAll/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<ul>
|
||||
<li>Example</li>
|
||||
<li>Example</li>
|
||||
<li>Example</li>
|
||||
</ul>
|
||||
<script>
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<ul>
|
||||
<li>Example</li>
|
||||
<li>Example</li>
|
||||
<li>Example</li>
|
||||
</ul>
|
||||
<script>
|
||||
d3.selectAll("li")
|
||||
.text("list item")
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,109 @@
|
||||
---
|
||||
id: 587d7fac367417b2b2512bdb
|
||||
title: Set a Domain and a Range on a Scale
|
||||
challengeType: 6
|
||||
forumTopicId: 301491
|
||||
dashedName: set-a-domain-and-a-range-on-a-scale
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
By default, scales use the identity relationship. This means the input value maps to the output value. However, scales can be much more flexible and interesting.
|
||||
|
||||
Say a dataset has values ranging from 50 to 480. This is the input information for a scale, also known as the <dfn>domain</dfn>.
|
||||
|
||||
You want to map those points along the `x` axis on the SVG canvas, between 10 units and 500 units. This is the output information, also known as the <dfn>range</dfn>.
|
||||
|
||||
The `domain()` and `range()` methods set these values for the scale. Both methods take an array of at least two elements as an argument. Here's an example:
|
||||
|
||||
```js
|
||||
// Set a domain
|
||||
// The domain covers the set of input values
|
||||
scale.domain([50, 480]);
|
||||
// Set a range
|
||||
// The range covers the set of output values
|
||||
scale.range([10, 500]);
|
||||
scale(50) // Returns 10
|
||||
scale(480) // Returns 500
|
||||
scale(325) // Returns 323.37
|
||||
scale(750) // Returns 807.67
|
||||
d3.scaleLinear()
|
||||
```
|
||||
|
||||
Notice that the scale uses the linear relationship between the domain and range values to figure out what the output should be for a given number. The minimum value in the domain (50) maps to the minimum value (10) in the range.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Create a scale and set its domain to `[250, 500]` and range to `[10, 150]`.
|
||||
|
||||
**Note**
|
||||
You can chain the `domain()` and `range()` methods onto the `scale` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use the `domain()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.domain/g));
|
||||
```
|
||||
|
||||
The `domain()` of the scale should be set to `[250, 500]`.
|
||||
|
||||
```js
|
||||
assert(JSON.stringify(scale.domain()) == JSON.stringify([250, 500]));
|
||||
```
|
||||
|
||||
Your code should use the `range()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.range/g));
|
||||
```
|
||||
|
||||
The `range()` of the scale should be set to `[10, 150]`.
|
||||
|
||||
```js
|
||||
assert(JSON.stringify(scale.range()) == JSON.stringify([10, 150]));
|
||||
```
|
||||
|
||||
The text in the `h2` should be -102.
|
||||
|
||||
```js
|
||||
assert($('h2').text() == '-102');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
// Add your code below this line
|
||||
const scale = d3.scaleLinear();
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
const output = scale(50);
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output);
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const scale = d3.scaleLinear();
|
||||
scale.domain([250, 500])
|
||||
scale.range([10, 150])
|
||||
const output = scale(50);
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output);
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,110 @@
|
||||
---
|
||||
id: 587d7faa367417b2b2512bd3
|
||||
title: Style D3 Labels
|
||||
challengeType: 6
|
||||
forumTopicId: 301492
|
||||
dashedName: style-d3-labels
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
D3 methods can add styles to the bar labels. The `fill` attribute sets the color of the text for a `text` node. The `style()` method sets CSS rules for other styles, such as "font-family" or "font-size".
|
||||
|
||||
# --instructions--
|
||||
|
||||
Set the `font-size` of the `text` elements to 25px, and the color of the text to red.
|
||||
|
||||
# --hints--
|
||||
|
||||
The labels should all have a `fill` color of red.
|
||||
|
||||
```js
|
||||
assert($('text').css('fill') == 'rgb(255, 0, 0)');
|
||||
```
|
||||
|
||||
The labels should all have a `font-size` of 25 pixels.
|
||||
|
||||
```js
|
||||
assert($('text').css('font-size') == '25px');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => d * 3)
|
||||
.attr("fill", "navy");
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (3 * d) - 3)
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
const w = 500;
|
||||
const h = 100;
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("rect")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("rect")
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - 3 * d)
|
||||
.attr("width", 25)
|
||||
.attr("height", (d, i) => d * 3)
|
||||
.attr("fill", "navy");
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => d)
|
||||
.attr("x", (d, i) => i * 30)
|
||||
.attr("y", (d, i) => h - (3 * d) - 3)
|
||||
.style("font-size", 25)
|
||||
.attr("fill", "red")
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,135 @@
|
||||
---
|
||||
id: 587d7fa8367417b2b2512bc9
|
||||
title: Update the Height of an Element Dynamically
|
||||
challengeType: 6
|
||||
forumTopicId: 301493
|
||||
dashedName: update-the-height-of-an-element-dynamically
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The previous challenges covered how to display data from an array and how to add CSS classes. You can combine these lessons to create a simple bar chart. There are two steps to this:
|
||||
|
||||
1) Create a `div` for each data point in the array
|
||||
|
||||
2) Give each `div` a dynamic height, using a callback function in the `style()` method that sets height equal to the data value
|
||||
|
||||
Recall the format to set a style using a callback function:
|
||||
|
||||
`selection.style("cssProperty", (d) => d)`
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add the `style()` method to the code in the editor to set the `height` property for each element. Use a callback function to return the value of the data point with the string "px" added to it.
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `div` should have a `height` of 12 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(0)[0].style.height === '12px');
|
||||
```
|
||||
|
||||
The second `div` should have a `height` of 31 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(1)[0].style.height === '31px');
|
||||
```
|
||||
|
||||
The third `div` should have a `height` of 22 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(2)[0].style.height === '22px');
|
||||
```
|
||||
|
||||
The fourth `div` should have a `height` of 17 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(3)[0].style.height === '17px');
|
||||
```
|
||||
|
||||
The fifth `div` should have a `height` of 25 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(4)[0].style.height === '25px');
|
||||
```
|
||||
|
||||
The sixth `div` should have a `height` of 18 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(5)[0].style.height === '18px');
|
||||
```
|
||||
|
||||
The seventh `div` should have a `height` of 29 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(6)[0].style.height === '29px');
|
||||
```
|
||||
|
||||
The eighth `div` should have a `height` of 14 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(7)[0].style.height === '14px');
|
||||
```
|
||||
|
||||
The ninth `div` should have a `height` of 9 pixels.
|
||||
|
||||
```js
|
||||
assert($('div').eq(8)[0].style.height === '9px');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
.attr("class", "bar")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<style>
|
||||
.bar {
|
||||
width: 25px;
|
||||
height: 100px;
|
||||
display: inline-block;
|
||||
background-color: blue;
|
||||
}
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("div")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("div")
|
||||
.attr("class", "bar")
|
||||
.style('height', d => `${d}px`)
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,347 @@
|
||||
---
|
||||
id: 587d7fac367417b2b2512bde
|
||||
title: Use a Pre-Defined Scale to Place Elements
|
||||
challengeType: 6
|
||||
forumTopicId: 301494
|
||||
dashedName: use-a-pre-defined-scale-to-place-elements
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
With the scales set up, it's time to map the scatter plot again. The scales are like processing functions that turn the x and y raw data into values that fit and render correctly on the SVG canvas. They keep the data within the screen's plotting area.
|
||||
|
||||
You set the coordinate attribute values for an SVG shape with the scaling function. This includes `x` and `y` attributes for `rect` or `text` elements, or `cx` and `cy` for `circles`. Here's an example:
|
||||
|
||||
```js
|
||||
shape
|
||||
.attr("x", (d) => xScale(d[0]))
|
||||
```
|
||||
|
||||
Scales set shape coordinate attributes to place the data points onto the SVG canvas. You don't need to apply scales when you display the actual data value, for example, in the `text()` method for a tooltip or label.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use `xScale` and `yScale` to position both the `circle` and `text` shapes onto the SVG canvas. For the `circles`, apply the scales to set the `cx` and `cy` attributes. Give them a radius of 5 units, too.
|
||||
|
||||
For the `text` elements, apply the scales to set the `x` and `y` attributes. The labels should be offset to the right of the dots. To do this, add 10 units to the x data value before passing it to the `xScale`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should have 10 `circle` elements.
|
||||
|
||||
```js
|
||||
assert($('circle').length == 10);
|
||||
```
|
||||
|
||||
The first `circle` element should have a `cx` value of approximately 91 and a `cy` value of approximately 368 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(0).attr('cx')) == '91' &&
|
||||
Math.round($('circle').eq(0).attr('cy')) == '368' &&
|
||||
$('circle').eq(0).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The second `circle` element should have a `cx` value of approximately 159 and a `cy` value of approximately 181 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(1).attr('cx')) == '159' &&
|
||||
Math.round($('circle').eq(1).attr('cy')) == '181' &&
|
||||
$('circle').eq(1).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The third `circle` element should have a `cx` value of approximately 340 and a `cy` value of approximately 329 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(2).attr('cx')) == '340' &&
|
||||
Math.round($('circle').eq(2).attr('cy')) == '329' &&
|
||||
$('circle').eq(2).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The fourth `circle` element should have a `cx` value of approximately 131 and a `cy` value of approximately 60 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(3).attr('cx')) == '131' &&
|
||||
Math.round($('circle').eq(3).attr('cy')) == '60' &&
|
||||
$('circle').eq(3).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The fifth `circle` element should have a `cx` value of approximately 440 and a `cy` value of approximately 237 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(4).attr('cx')) == '440' &&
|
||||
Math.round($('circle').eq(4).attr('cy')) == '237' &&
|
||||
$('circle').eq(4).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The sixth `circle` element should have a `cx` value of approximately 271 and a `cy` value of approximately 306 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(5).attr('cx')) == '271' &&
|
||||
Math.round($('circle').eq(5).attr('cy')) == '306' &&
|
||||
$('circle').eq(5).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The seventh `circle` element should have a `cx` value of approximately 361 and a `cy` value of approximately 351 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(6).attr('cx')) == '361' &&
|
||||
Math.round($('circle').eq(6).attr('cy')) == '351' &&
|
||||
$('circle').eq(6).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The eighth `circle` element should have a `cx` value of approximately 261 and a `cy` value of approximately 132 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(7).attr('cx')) == '261' &&
|
||||
Math.round($('circle').eq(7).attr('cy')) == '132' &&
|
||||
$('circle').eq(7).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The ninth `circle` element should have a `cx` value of approximately 131 and a `cy` value of approximately 144 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(8).attr('cx')) == '131' &&
|
||||
Math.round($('circle').eq(8).attr('cy')) == '144' &&
|
||||
$('circle').eq(8).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
The tenth `circle` element should have a `cx` value of approximately 79 and a `cy` value of approximately 326 after applying the scales. It should also have an `r` value of 5.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('circle').eq(9).attr('cx')) == '79' &&
|
||||
Math.round($('circle').eq(9).attr('cy')) == '326' &&
|
||||
$('circle').eq(9).attr('r') == '5'
|
||||
);
|
||||
```
|
||||
|
||||
Your code should have 10 `text` elements.
|
||||
|
||||
```js
|
||||
assert($('text').length == 10);
|
||||
```
|
||||
|
||||
The first label should have an `x` value of approximately 100 and a `y` value of approximately 368 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(0).attr('x')) == '100' &&
|
||||
Math.round($('text').eq(0).attr('y')) == '368'
|
||||
);
|
||||
```
|
||||
|
||||
The second label should have an `x` value of approximately 168 and a `y` value of approximately 181 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(1).attr('x')) == '168' &&
|
||||
Math.round($('text').eq(1).attr('y')) == '181'
|
||||
);
|
||||
```
|
||||
|
||||
The third label should have an `x` value of approximately 350 and a `y` value of approximately 329 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(2).attr('x')) == '350' &&
|
||||
Math.round($('text').eq(2).attr('y')) == '329'
|
||||
);
|
||||
```
|
||||
|
||||
The fourth label should have an `x` value of approximately 141 and a `y` value of approximately 60 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(3).attr('x')) == '141' &&
|
||||
Math.round($('text').eq(3).attr('y')) == '60'
|
||||
);
|
||||
```
|
||||
|
||||
The fifth label should have an `x` value of approximately 449 and a `y` value of approximately 237 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(4).attr('x')) == '449' &&
|
||||
Math.round($('text').eq(4).attr('y')) == '237'
|
||||
);
|
||||
```
|
||||
|
||||
The sixth label should have an `x` value of approximately 280 and a `y` value of approximately 306 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(5).attr('x')) == '280' &&
|
||||
Math.round($('text').eq(5).attr('y')) == '306'
|
||||
);
|
||||
```
|
||||
|
||||
The seventh label should have an `x` value of approximately 370 and a `y` value of approximately 351 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(6).attr('x')) == '370' &&
|
||||
Math.round($('text').eq(6).attr('y')) == '351'
|
||||
);
|
||||
```
|
||||
|
||||
The eighth label should have an `x` value of approximately 270 and a `y` value of approximately 132 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(7).attr('x')) == '270' &&
|
||||
Math.round($('text').eq(7).attr('y')) == '132'
|
||||
);
|
||||
```
|
||||
|
||||
The ninth label should have an `x` value of approximately 140 and a `y` value of approximately 144 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(8).attr('x')) == '140' &&
|
||||
Math.round($('text').eq(8).attr('y')) == '144'
|
||||
);
|
||||
```
|
||||
|
||||
The tenth label should have an `x` value of approximately 88 and a `y` value of approximately 326 after applying the scales.
|
||||
|
||||
```js
|
||||
assert(
|
||||
Math.round($('text').eq(9).attr('x')) == '88' &&
|
||||
Math.round($('text').eq(9).attr('y')) == '326'
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
const padding = 60;
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[1])])
|
||||
.range([h - padding, padding]);
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => (d[0] + ", "
|
||||
+ d[1]))
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
const padding = 60;
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[1])])
|
||||
.range([h - padding, padding]);
|
||||
|
||||
const svg = d3.select("body")
|
||||
.append("svg")
|
||||
.attr("width", w)
|
||||
.attr("height", h);
|
||||
|
||||
svg.selectAll("circle")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("circle")
|
||||
.attr("cx", (d) => xScale(d[0]))
|
||||
.attr("cy", (d) => yScale(d[1]))
|
||||
.attr("r", 5)
|
||||
|
||||
svg.selectAll("text")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("text")
|
||||
.text((d) => (d[0] + ", "
|
||||
+ d[1]))
|
||||
.attr("x", (d) => xScale(d[0] + 10))
|
||||
.attr("y", (d) => yScale(d[1]))
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,158 @@
|
||||
---
|
||||
id: 587d7fac367417b2b2512bdd
|
||||
title: Use Dynamic Scales
|
||||
challengeType: 6
|
||||
forumTopicId: 301495
|
||||
dashedName: use-dynamic-scales
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The D3 `min()` and `max()` methods are useful to help set the scale.
|
||||
|
||||
Given a complex data set, one priority is to set the scale so the visualization fits the SVG container's width and height. You want all the data plotted inside the SVG canvas so it's visible on the web page.
|
||||
|
||||
The example below sets the x-axis scale for scatter plot data. The `domain()` method passes information to the scale about the raw data values for the plot. The `range()` method gives it information about the actual space on the web page for the visualization.
|
||||
|
||||
In the example, the domain goes from 0 to the maximum in the set. It uses the `max()` method with a callback function based on the x values in the arrays. The range uses the SVG canvas' width (`w`), but it includes some padding, too. This puts space between the scatter plot dots and the edge of the SVG canvas.
|
||||
|
||||
```js
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
// Padding between the SVG canvas boundary and the plot
|
||||
const padding = 30;
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
```
|
||||
|
||||
The padding may be confusing at first. Picture the x-axis as a horizontal line from 0 to 500 (the width value for the SVG canvas). Including the padding in the `range()` method forces the plot to start at 30 along that line (instead of 0), and end at 470 (instead of 500).
|
||||
|
||||
# --instructions--
|
||||
|
||||
Use the `yScale` variable to create a linear y-axis scale. The domain should start at zero and go to the maximum y value in the set. The range should use the SVG height (`h`) and include padding.
|
||||
|
||||
**Note**
|
||||
Remember to keep the plot right-side-up. When you set the range for the y coordinates, the higher value (height minus padding) is the first argument, and the lower value is the second argument.
|
||||
|
||||
# --hints--
|
||||
|
||||
The text in the `h2` should be 30.
|
||||
|
||||
```js
|
||||
assert(output == 30 && $('h2').text() == '30');
|
||||
```
|
||||
|
||||
The `domain()` of yScale should be equivalent to `[0, 411]`.
|
||||
|
||||
```js
|
||||
assert(JSON.stringify(yScale.domain()) == JSON.stringify([0, 411]));
|
||||
```
|
||||
|
||||
The `range()` of yScale should be equivalent to `[470, 30]`.
|
||||
|
||||
```js
|
||||
assert(JSON.stringify(yScale.range()) == JSON.stringify([470, 30]));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
// Padding between the SVG canvas boundary and the plot
|
||||
const padding = 30;
|
||||
|
||||
// Create an x and y scale
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
// Add your code below this line
|
||||
|
||||
const yScale = undefined;
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
const output = yScale(411); // Returns 30
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output)
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [
|
||||
[ 34, 78 ],
|
||||
[ 109, 280 ],
|
||||
[ 310, 120 ],
|
||||
[ 79, 411 ],
|
||||
[ 420, 220 ],
|
||||
[ 233, 145 ],
|
||||
[ 333, 96 ],
|
||||
[ 222, 333 ],
|
||||
[ 78, 320 ],
|
||||
[ 21, 123 ]
|
||||
];
|
||||
|
||||
const w = 500;
|
||||
const h = 500;
|
||||
|
||||
|
||||
const padding = 30;
|
||||
|
||||
const xScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[0])])
|
||||
.range([padding, w - padding]);
|
||||
|
||||
|
||||
const yScale = d3.scaleLinear()
|
||||
.domain([0, d3.max(dataset, (d) => d[1])])
|
||||
.range([h - padding, padding]);
|
||||
|
||||
|
||||
const output = yScale(411);
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output)
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,90 @@
|
||||
---
|
||||
id: 587d7fac367417b2b2512bdc
|
||||
title: >-
|
||||
Use the d3.max and d3.min Functions to Find Minimum and Maximum Values in a Dataset
|
||||
challengeType: 6
|
||||
forumTopicId: 301496
|
||||
dashedName: >-
|
||||
use-the-d3-max-and-d3-min-functions-to-find-minimum-and-maximum-values-in-a-dataset
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The D3 methods `domain()` and `range()` set that information for your scale based on the data. There are a couple methods to make that easier.
|
||||
|
||||
Often when you set the domain, you'll want to use the minimum and maximum values within the data set. Trying to find these values manually, especially in a large data set, may cause errors.
|
||||
|
||||
D3 has two methods - `min()` and `max()` to return this information. Here's an example:
|
||||
|
||||
```js
|
||||
const exampleData = [34, 234, 73, 90, 6, 52];
|
||||
d3.min(exampleData) // Returns 6
|
||||
d3.max(exampleData) // Returns 234
|
||||
```
|
||||
|
||||
A dataset may have nested arrays, like the \[x, y] coordinate pairs that were in the scatter plot example. In that case, you need to tell D3 how to calculate the maximum and minimum. Fortunately, both the `min()` and `max()` methods take a callback function. In this example, the callback function's argument `d` is for the current inner array. The callback needs to return the element from the inner array (the x or y value) over which you want to compute the maximum or minimum. Here's an example for how to find the min and max values with an array of arrays:
|
||||
|
||||
```js
|
||||
const locationData = [[1, 7],[6, 3],[8, 3]];
|
||||
// Returns the smallest number out of the first elements
|
||||
const minX = d3.min(locationData, (d) => d[0]);
|
||||
// minX compared 1, 6, and 8 and is set to 1
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
The `positionData` array holds sub arrays of x, y, and z coordinates. Use a D3 method to find the maximum value of the z coordinate (the third value) from the arrays and save it in the `output` variable.
|
||||
|
||||
# --hints--
|
||||
|
||||
The text in the `h2` should be 8.
|
||||
|
||||
```js
|
||||
assert(output == 8 && $('h2').text() == '8');
|
||||
```
|
||||
|
||||
Your code should use the `max()` method.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(/\.max/g),
|
||||
'Your code should use the <code>max()</code> method.'
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const positionData = [[1, 7, -4],[6, 3, 8],[2, 9, 3]]
|
||||
// Add your code below this line
|
||||
|
||||
const output = undefined; // Change this line
|
||||
|
||||
// Add your code above this line
|
||||
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output)
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const positionData = [[1, 7, -4],[6, 3, 8],[2, 9, 3]]
|
||||
|
||||
const output = d3.max(positionData, (d) => d[2])
|
||||
|
||||
d3.select("body")
|
||||
.append("h2")
|
||||
.text(output)
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,105 @@
|
||||
---
|
||||
id: 587d7fa7367417b2b2512bc4
|
||||
title: Work with Data in D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301497
|
||||
dashedName: work-with-data-in-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The D3 library focuses on a data-driven approach. When you have a set of data, you can apply D3 methods to display it on the page. Data comes in many formats, but this challenge uses a simple array of numbers.
|
||||
|
||||
The first step is to make D3 aware of the data. The `data()` method is used on a selection of DOM elements to attach the data to those elements. The data set is passed as an argument to the method.
|
||||
|
||||
A common workflow pattern is to create a new element in the document for each piece of data in the set. D3 has the `enter()` method for this purpose.
|
||||
|
||||
When `enter()` is combined with the `data()` method, it looks at the selected elements from the page and compares them to the number of data items in the set. If there are fewer elements than data items, it creates the missing elements.
|
||||
|
||||
Here is an example that selects a `ul` element and creates a new list item based on the number of entries in the array:
|
||||
|
||||
```html
|
||||
<body>
|
||||
<ul></ul>
|
||||
<script>
|
||||
const dataset = ["a", "b", "c"];
|
||||
d3.select("ul").selectAll("li")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("li")
|
||||
.text("New item");
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
It may seem confusing to select elements that don't exist yet. This code is telling D3 to first select the `ul` on the page. Next, select all list items, which returns an empty selection. Then the `data()` method reviews the dataset and runs the following code three times, once for each item in the array. The `enter()` method sees there are no `li` elements on the page, but it needs 3 (one for each piece of data in `dataset`). New `li` elements are appended to the `ul` and have the text "New item".
|
||||
|
||||
# --instructions--
|
||||
|
||||
Select the `body` node, then select all `h2` elements. Have D3 create and append an `h2` tag for each item in the `dataset` array. The text in the `h2` should say "New Title". Your code should use the `data()` and `enter()` methods.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your document should have 9 `h2` elements.
|
||||
|
||||
```js
|
||||
assert($('h2').length == 9);
|
||||
```
|
||||
|
||||
The text in the `h2` elements should say "New Title". The capitalization and spacing should match exactly.
|
||||
|
||||
```js
|
||||
assert(
|
||||
$('h2')
|
||||
.text()
|
||||
.match(/New Title/g).length == 9
|
||||
);
|
||||
```
|
||||
|
||||
Your code should use the `data()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.data/g));
|
||||
```
|
||||
|
||||
Your code should use the `enter()` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.enter/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body")
|
||||
.selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text("New Title")
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,120 @@
|
||||
---
|
||||
id: 587d7fa7367417b2b2512bc5
|
||||
title: Work with Dynamic Data in D3
|
||||
challengeType: 6
|
||||
forumTopicId: 301498
|
||||
dashedName: work-with-dynamic-data-in-d3
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last two challenges cover the basics of displaying data dynamically with D3 using the `data()` and `enter()` methods. These methods take a data set and, together with the `append()` method, create a new DOM element for each entry in the data set.
|
||||
|
||||
In the previous challenge, you created a new `h2` element for each item in the `dataset` array, but they all contained the same text, "New Title". This is because you have not made use of the data that is bound to each of the `h2` elements.
|
||||
|
||||
The D3 `text()` method can take a string or a callback function as an argument:
|
||||
|
||||
`selection.text((d) => d)`
|
||||
|
||||
In the example above, the parameter `d` refers to a single entry in the dataset that a selection is bound to.
|
||||
|
||||
Using the current example as context, the first `h2` element is bound to 12, the second `h2` element is bound to 31, the third `h2` element is bound to 22, and so on.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Change the `text()` method so that each `h2` element displays the corresponding value from the `dataset` array with a single space and "USD". For example, the first heading should be "12 USD".
|
||||
|
||||
# --hints--
|
||||
|
||||
The first `h2` should have the text "12 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(0).text() == '12 USD');
|
||||
```
|
||||
|
||||
The second `h2` should have the text "31 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(1).text() == '31 USD');
|
||||
```
|
||||
|
||||
The third `h2` should have the text "22 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(2).text() == '22 USD');
|
||||
```
|
||||
|
||||
The fourth `h2` should have the text "17 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(3).text() == '17 USD');
|
||||
```
|
||||
|
||||
The fifth `h2` should have the text "25 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(4).text() == '25 USD');
|
||||
```
|
||||
|
||||
The sixth `h2` should have the text "18 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(5).text() == '18 USD');
|
||||
```
|
||||
|
||||
The seventh `h2` should have the text "29 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(6).text() == '29 USD');
|
||||
```
|
||||
|
||||
The eighth `h2` should have the text "14 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(7).text() == '14 USD');
|
||||
```
|
||||
|
||||
The ninth `h2` should have the text "9 USD".
|
||||
|
||||
```js
|
||||
assert($('h2').eq(8).text() == '9 USD');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
// Add your code below this line
|
||||
|
||||
.text("New Title");
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
</body>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<body>
|
||||
<script>
|
||||
const dataset = [12, 31, 22, 17, 25, 18, 29, 14, 9];
|
||||
|
||||
d3.select("body").selectAll("h2")
|
||||
.data(dataset)
|
||||
.enter()
|
||||
.append("h2")
|
||||
.text((d) => `${d} USD`);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
```
|
@ -0,0 +1,166 @@
|
||||
---
|
||||
id: 587d7fae367417b2b2512be4
|
||||
title: Access the JSON Data from an API
|
||||
challengeType: 6
|
||||
forumTopicId: 301499
|
||||
dashedName: access-the-json-data-from-an-api
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In the previous challenge, you saw how to get JSON data from the freeCodeCamp Cat Photo API.
|
||||
|
||||
Now you'll take a closer look at the returned data to better understand the JSON format. Recall some notation in JavaScript:
|
||||
|
||||
<blockquote>[ ] -> Square brackets represent an array<br>{ } -> Curly brackets represent an object<br>" " -> Double quotes represent a string. They are also used for key names in JSON</blockquote>
|
||||
|
||||
Understanding the structure of the data that an API returns is important because it influences how you retrieve the values you need.
|
||||
|
||||
On the right, click the "Get Message" button to load the freeCodeCamp Cat Photo API JSON into the HTML.
|
||||
|
||||
The first and last character you see in the JSON data are square brackets `[ ]`. This means that the returned data is an array. The second character in the JSON data is a curly `{` bracket, which starts an object. Looking closely, you can see that there are three separate objects. The JSON data is an array of three objects, where each object contains information about a cat photo.
|
||||
|
||||
You learned earlier that objects contain "key-value pairs" that are separated by commas. In the Cat Photo example, the first object has `"id":0` where "id" is a key and 0 is its corresponding value. Similarly, there are keys for "imageLink", "altText", and "codeNames". Each cat photo object has these same keys, but with different values.
|
||||
|
||||
Another interesting "key-value pair" in the first object is `"codeNames":["Juggernaut","Mrs. Wallace","ButterCup"]`. Here "codeNames" is the key and its value is an array of three strings. It's possible to have arrays of objects as well as a key with an array as a value.
|
||||
|
||||
Remember how to access data in arrays and objects. Arrays use bracket notation to access a specific index of an item. Objects use either bracket or dot notation to access the value of a given property. Here's an example that prints the "altText" of the first cat photo - note that the parsed JSON data in the editor is saved in a variable called `json`:
|
||||
|
||||
```js
|
||||
console.log(json[0].altText);
|
||||
// Prints "A white cat wearing a green helmet shaped melon on its head."
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
For the cat with the "id" of 2, print to the console the second value in the `codeNames` array. You should use bracket and dot notation on the object (which is saved in the variable `json`) to access the value.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use bracket and dot notation to access the proper code name, and print "Loki" to the console.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/console\s*\.\s*log\s*\(\s*json\s*\[2\]\s*(\.\s*codeNames|\[\s*('|`|")codeNames\2\s*\])\s*\[\s*1\s*\]\s*\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json', true);
|
||||
req.send();
|
||||
req.onload=function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
document.getElementsByClassName('message')[0].innerHTML = JSON.stringify(json);
|
||||
// Add your code below this line
|
||||
|
||||
// Add your code above this line
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json', true);
|
||||
req.send();
|
||||
req.onload=function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
document.getElementsByClassName('message')[0].innerHTML = JSON.stringify(json);
|
||||
// Add your code below this line
|
||||
console.log(json[2].codeNames[1]);
|
||||
// Add your code above this line
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,138 @@
|
||||
---
|
||||
id: 587d7fad367417b2b2512be2
|
||||
title: Change Text with click Events
|
||||
challengeType: 6
|
||||
forumTopicId: 301500
|
||||
dashedName: change-text-with-click-events
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
When the click event happens, you can use JavaScript to update an HTML element.
|
||||
|
||||
For example, when a user clicks the "Get Message" button, it changes the text of the element with the class `message` to say "Here is the message".
|
||||
|
||||
This works by adding the following code within the click event:
|
||||
|
||||
`document.getElementsByClassName('message')[0].textContent="Here is the message";`
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add code inside the `onclick` event handler to change the text inside the `message` element to say "Here is the message".
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use the `document.getElementsByClassName` method to select the element with class `message` and set its `textContent` to the given string.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/document\s*\.getElementsByClassName\(\s*?('|")message\1\s*?\)\[0\]\s*\.textContent\s*?=\s*?('|")Here is the message\2/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded',function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
// Add your code below this line
|
||||
document.getElementsByClassName('message')[0].textContent = "Here is the message";
|
||||
// Add your code above this line
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,199 @@
|
||||
---
|
||||
id: 587d7fae367417b2b2512be5
|
||||
title: Convert JSON Data to HTML
|
||||
challengeType: 6
|
||||
forumTopicId: 16807
|
||||
dashedName: convert-json-data-to-html
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that you're getting data from a JSON API, you can display it in the HTML.
|
||||
|
||||
You can use a `forEach` method to loop through the data since the cat photo objects are held in an array. As you get to each item, you can modify the HTML elements.
|
||||
|
||||
First, declare an html variable with `let html = "";`.
|
||||
|
||||
Then, loop through the JSON, adding HTML to the variable that wraps the key names in `strong` tags, followed by the value. When the loop is finished, you render it.
|
||||
|
||||
Here's the code that does this:
|
||||
|
||||
```js
|
||||
let html = "";
|
||||
json.forEach(function(val) {
|
||||
const keys = Object.keys(val);
|
||||
html += "<div class = 'cat'>";
|
||||
keys.forEach(function(key) {
|
||||
html += "<strong>" + key + "</strong>: " + val[key] + "<br>";
|
||||
});
|
||||
html += "</div><br>";
|
||||
});
|
||||
```
|
||||
|
||||
**Note:** For this challenge, you need to add new HTML elements to the page, so you cannot rely on `textContent`. Instead, you need to use `innerHTML`, which can make a site vulnerable to Cross-site scripting attacks.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add a `forEach` method to loop over the JSON data and create the HTML elements to display it.
|
||||
|
||||
Here is some example JSON
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id":0,
|
||||
"imageLink":"https://s3.amazonaws.com/freecodecamp/funny-cat.jpg",
|
||||
"altText":"A white cat wearing a green helmet shaped melon on its head. ",
|
||||
"codeNames":[ "Juggernaut", "Mrs. Wallace", "Buttercup"
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should store the data in the `html` variable
|
||||
|
||||
```js
|
||||
assert(code.match(/html\s+?(\+=|=\shtml\s\+)/g));
|
||||
```
|
||||
|
||||
Your code should use a `forEach` method to loop over the JSON data from the API.
|
||||
|
||||
```js
|
||||
assert(code.match(/json\.forEach/g));
|
||||
```
|
||||
|
||||
Your code should wrap the key names in `strong` tags.
|
||||
|
||||
```js
|
||||
assert(code.match(/<strong>.+<\/strong>/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json',true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
document.getElementsByClassName('message')[0].innerHTML = html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json',true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
// Add your code below this line
|
||||
json.forEach(function(val) {
|
||||
var keys = Object.keys(val);
|
||||
html += "<div class = 'cat'>";
|
||||
keys.forEach(function(key) {
|
||||
html += "<strong>" + key + "</strong>: " + val[key] + "<br>";
|
||||
});
|
||||
html += "</div><br>";
|
||||
});
|
||||
// Add your code above this line
|
||||
document.getElementsByClassName('message')[0].innerHTML = html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,98 @@
|
||||
---
|
||||
id: 587d7faf367417b2b2512be8
|
||||
title: Get Geolocation Data to Find A User's GPS Coordinates
|
||||
challengeType: 6
|
||||
forumTopicId: 18188
|
||||
dashedName: get-geolocation-data-to-find-a-users-gps-coordinates
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another cool thing you can do is access your user's current location. Every browser has a built in navigator that can give you this information.
|
||||
|
||||
The navigator will get the user's current longitude and latitude.
|
||||
|
||||
You will see a prompt to allow or block this site from knowing your current location. The challenge can be completed either way, as long as the code is correct.
|
||||
|
||||
By selecting allow, you will see the text on the output phone change to your latitude and longitude.
|
||||
|
||||
Here's code that does this:
|
||||
|
||||
```js
|
||||
if (navigator.geolocation){
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
document.getElementById('data').innerHTML="latitude: " + position.coords.latitude + "<br>longitude: " + position.coords.longitude;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
First, it checks if the `navigator.geolocation` object exists. If it does, the `getCurrentPosition` method on that object is called, which initiates an asynchronous request for the user's position. If the request is successful, the callback function in the method runs. This function accesses the `position` object's values for latitude and longitude using dot notation and updates the HTML.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add the example code inside the `script` tags to check a user's current location and insert it into the HTML.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use `navigator.geolocation` to access the user's current location.
|
||||
|
||||
```js
|
||||
assert(code.match(/navigator\.geolocation\.getCurrentPosition/g));
|
||||
```
|
||||
|
||||
Your code should use `position.coords.latitude` to display the user's latitudinal location.
|
||||
|
||||
```js
|
||||
assert(code.match(/position\.coords\.latitude/g));
|
||||
```
|
||||
|
||||
Your code should use `position.coords.longitude` to display the user's longitudinal location.
|
||||
|
||||
```js
|
||||
assert(code.match(/position\.coords\.longitude/g));
|
||||
```
|
||||
|
||||
You should display the user's position within the `data` div element.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(/document\.getElementById\(\s*?('|")data\1\s*?\)\.innerHTML/g)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
</script>
|
||||
<h4>You are here:</h4>
|
||||
<div id="data">
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
// Add your code below this line
|
||||
if (navigator.geolocation) {
|
||||
navigator.geolocation.getCurrentPosition(function(position) {
|
||||
document.getElementById('data').innerHTML = "latitude: " + position.coords.latitude + "<br>longitude: " + position.coords.longitude;
|
||||
});
|
||||
}
|
||||
// Add your code above this line
|
||||
</script>
|
||||
<h4>You are here:</h4>
|
||||
<div id="data">
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
```
|
@ -0,0 +1,174 @@
|
||||
---
|
||||
id: 5ccfad82bb2dc6c965a848e5
|
||||
title: Get JSON with the JavaScript fetch method
|
||||
challengeType: 6
|
||||
forumTopicId: 301501
|
||||
dashedName: get-json-with-the-javascript-fetch-method
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Another way to request external data is to use the JavaScript `fetch()` method. It is equivalent to XMLHttpRequest, but the syntax is considered easier to understand.
|
||||
|
||||
Here is the code for making a GET request to `/json/cats.json`
|
||||
|
||||
```js
|
||||
|
||||
fetch('/json/cats.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('message').innerHTML = JSON.stringify(data);
|
||||
})
|
||||
|
||||
```
|
||||
|
||||
Take a look at each piece of this code.
|
||||
|
||||
The first line is the one that makes the request. So, `fetch(URL)` makes a GET request to the URL specified. The method returns a Promise.
|
||||
|
||||
After a Promise is returned, if the request was successful, the `then` method is executed, which takes the response and converts it to JSON format.
|
||||
|
||||
The `then` method also returns a Promise, which is handled by the next `then` method. The argument in the second `then` is the JSON object you are looking for!
|
||||
|
||||
Now, it selects the element that will receive the data by using `document.getElementById()`. Then it modifies the HTML code of the element by inserting a string created from the JSON object returned from the request.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Update the code to create and send a "GET" request to the freeCodeCamp Cat Photo API. But this time, using the `fetch` method instead of `XMLHttpRequest`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should make a GET request with `fetch`.
|
||||
|
||||
```js
|
||||
assert(code.match(/fetch\s*\(\s*('|")\/json\/cats\.json\1\s*\)/g));
|
||||
```
|
||||
|
||||
Your code should use `then` to convert the response to JSON.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/\.then\s*\(\s*\(?(?<var>\w+)\)?\s*=>\s*\k<var>\s*\.json\s*\(\s*\)\s*\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should use `then` to handle the data converted to JSON by the other `then`.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.then\s*\(\s*(data|\(\s*data\s*\))\s*=>\s*{[^}]*}\s*\)/g));
|
||||
```
|
||||
|
||||
Your code should get the element with id `message` and change its inner HTML to the string of JSON data.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/document\s*\.getElementById\s*\(\s*('|")message\1\s*\)\s*\.innerHTML\s*=\s*JSON\s*\.\s*stringify\s*\(\s*data\s*\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded',function(){
|
||||
document.getElementById('getMessage').onclick= () => {
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p id="message" class="box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded',function(){
|
||||
document.getElementById('getMessage').onclick= () => {
|
||||
fetch('/json/cats.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('message').innerHTML=JSON.stringify(data);
|
||||
})
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p id="message" class="box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,196 @@
|
||||
---
|
||||
id: 587d7fae367417b2b2512be3
|
||||
title: Get JSON with the JavaScript XMLHttpRequest Method
|
||||
challengeType: 6
|
||||
forumTopicId: 301502
|
||||
dashedName: get-json-with-the-javascript-xmlhttprequest-method
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You can also request data from an external source. This is where APIs come into play.
|
||||
|
||||
Remember that APIs - or Application Programming Interfaces - are tools that computers use to communicate with one another. You'll learn how to update HTML with the data we get from APIs using a technology called AJAX.
|
||||
|
||||
Most web APIs transfer data in a format called JSON. JSON stands for JavaScript Object Notation.
|
||||
|
||||
JSON syntax looks very similar to JavaScript object literal notation. JSON has object properties and their current values, sandwiched between a `{` and a `}`.
|
||||
|
||||
These properties and their values are often referred to as "key-value pairs".
|
||||
|
||||
However, JSON transmitted by APIs are sent as `bytes`, and your application receives it as a `string`. These can be converted into JavaScript objects, but they are not JavaScript objects by default. The `JSON.parse` method parses the string and constructs the JavaScript object described by it.
|
||||
|
||||
You can request the JSON from freeCodeCamp's Cat Photo API. Here's the code you can put in your click event to do this:
|
||||
|
||||
```js
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json',true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
document.getElementsByClassName('message')[0].innerHTML = JSON.stringify(json);
|
||||
};
|
||||
```
|
||||
|
||||
Here's a review of what each piece is doing. The JavaScript `XMLHttpRequest` object has a number of properties and methods that are used to transfer data. First, an instance of the `XMLHttpRequest` object is created and saved in the `req` variable. Next, the `open` method initializes a request - this example is requesting data from an API, therefore is a "GET" request. The second argument for `open` is the URL of the API you are requesting data from. The third argument is a Boolean value where `true` makes it an asynchronous request. The `send` method sends the request. Finally, the `onload` event handler parses the returned data and applies the `JSON.stringify` method to convert the JavaScript object into a string. This string is then inserted as the message text.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Update the code to create and send a "GET" request to the freeCodeCamp Cat Photo API. Then click the "Get Message" button. Your AJAX function will replace the "The message will go here" text with the raw JSON output from the API.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should create a new `XMLHttpRequest`.
|
||||
|
||||
```js
|
||||
assert(code.match(/new\s+?XMLHttpRequest\(\s*?\)/g));
|
||||
```
|
||||
|
||||
Your code should use the `open` method to initialize a "GET" request to the freeCodeCamp Cat Photo API.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/\.open\(\s*?('|")GET\1\s*?,\s*?('|")\/json\/cats\.json\2\s*?,\s*?true\s*?\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should use the `send` method to send the request.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.send\(\s*\)/g));
|
||||
```
|
||||
|
||||
Your code should have an `onload` event handler set to a function.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(/\.onload\s*=\s*(function|\(\s*?\))\s*?(\(\s*?\)|\=\>)\s*?{/g)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should use the `JSON.parse` method to parse the `responseText`.
|
||||
|
||||
```js
|
||||
assert(code.match(/JSON\s*\.parse\(\s*.*\.responseText\s*\)/g));
|
||||
```
|
||||
|
||||
Your code should get the element with class `message` and change its inner HTML to the string of JSON data.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/document\s*\.getElementsByClassName\(\s*?('|")message\1\s*?\)\[0\]\s*\.innerHTML\s*?=\s*?JSON\.stringify\(.+?\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded',function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('GET', '/json/cats.json', true);
|
||||
req.send();
|
||||
req.onload = () => {
|
||||
const json = JSON.parse(req.responseText);
|
||||
document.getElementsByClassName('message')[0].innerHTML = JSON.stringify(json);
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,140 @@
|
||||
---
|
||||
id: 587d7fad367417b2b2512be1
|
||||
title: Handle Click Events with JavaScript using the onclick property
|
||||
challengeType: 6
|
||||
forumTopicId: 301503
|
||||
dashedName: handle-click-events-with-javascript-using-the-onclick-property
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
You want your code to execute only once your page has finished loading. For that purpose, you can attach a JavaScript event to the document called `DOMContentLoaded`. Here's the code that does this:
|
||||
|
||||
```js
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
You can implement event handlers that go inside of the `DOMContentLoaded` function. You can implement an `onclick` event handler which triggers when the user clicks on the element with id `getMessage`, by adding the following code:
|
||||
|
||||
```js
|
||||
document.getElementById('getMessage').onclick = function(){};
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add a click event handler inside of the `DOMContentLoaded` function for the element with id of `getMessage`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use the `document.getElementById` method to select the `getMessage` element.
|
||||
|
||||
```js
|
||||
assert(code.match(/document\s*\.getElementById\(\s*?('|")getMessage\1\s*?\)/g));
|
||||
```
|
||||
|
||||
Your code should add an `onclick` event handler.
|
||||
|
||||
```js
|
||||
assert(typeof document.getElementById('getMessage').onclick === 'function');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
// Add your code below this line
|
||||
document.getElementById('getMessage').onclick = function(){ };
|
||||
// Add your code above this line
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,206 @@
|
||||
---
|
||||
id: 587d7faf367417b2b2512be9
|
||||
title: Post Data with the JavaScript XMLHttpRequest Method
|
||||
challengeType: 6
|
||||
forumTopicId: 301504
|
||||
dashedName: post-data-with-the-javascript-xmlhttprequest-method
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
In the previous examples, you received data from an external resource. You can also send data to an external resource, as long as that resource supports AJAX requests and you know the URL.
|
||||
|
||||
JavaScript's `XMLHttpRequest` method is also used to post data to a server. Here's an example:
|
||||
|
||||
```js
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 201){
|
||||
const serverResponse = JSON.parse(xhr.response);
|
||||
document.getElementsByClassName('message')[0].textContent = serverResponse.userName + serverResponse.suffix;
|
||||
}
|
||||
};
|
||||
const body = JSON.stringify({ userName: userName, suffix: ' loves cats!' });
|
||||
xhr.send(body);
|
||||
```
|
||||
|
||||
You've seen several of these methods before. Here the `open` method initializes the request as a "POST" to the given URL of the external resource, and uses the `true` Boolean to make it asynchronous. The `setRequestHeader` method sets the value of an HTTP request header, which contains information about the sender and the request. It must be called after the `open` method, but before the `send` method. The two parameters are the name of the header and the value to set as the body of that header. Next, the `onreadystatechange` event listener handles a change in the state of the request. A `readyState` of 4 means the operation is complete, and a `status` of 201 means it was a successful request. The document's HTML can be updated. Finally, the `send` method sends the request with the `body` value, which the `userName` key was given by the user in the `input` field.
|
||||
|
||||
# --instructions--
|
||||
|
||||
Update the code so it makes a "POST" request to the API endpoint. Then type your name in the input field and click "Send Message". Your AJAX function should replace "Reply from Server will be here." with data from the server. Format the response to display your name appended with " loves cats".
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should create a new `XMLHttpRequest`.
|
||||
|
||||
```js
|
||||
assert(code.match(/new\s+?XMLHttpRequest\(\s*?\)/g));
|
||||
```
|
||||
|
||||
Your code should use the `open` method to initialize a "POST" request to the server.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.open\(\s*?('|")POST\1\s*?,\s*?url\s*?,\s*?true\s*?\)/g));
|
||||
```
|
||||
|
||||
Your code should use the `setRequestHeader` method.
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/\.setRequestHeader\(\s*?('|")Content-Type\1\s*?,\s*?('|")application\/json;\s*charset=UTF-8\2\s*?\)/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should have an `onreadystatechange` event handler set to a function.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.onreadystatechange\s*?=/g));
|
||||
```
|
||||
|
||||
Your code should get the element with class `message` and change its `textContent` to "`userName` loves cats"
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(
|
||||
/document\.getElementsByClassName\(\s*?('|")message\1\s*?\)\[0\]\.textContent\s*?=\s*?.+?\.userName\s*?\+\s*?.+?\.suffix/g
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
Your code should use the `send` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/\.send\(\s*?body\s*?\)/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('sendMessage').onclick = function(){
|
||||
|
||||
const userName = document.getElementById('name').value;
|
||||
const url = 'https://jsonplaceholder.typicode.com/posts';
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Friends</h1>
|
||||
<p class="message box">
|
||||
Reply from Server will be here
|
||||
</p>
|
||||
<p>
|
||||
<label for="name">Your name:
|
||||
<input type="text" id="name"/>
|
||||
</label>
|
||||
<button id="sendMessage">
|
||||
Send Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('sendMessage').onclick = function(){
|
||||
|
||||
const userName = document.getElementById('name').value;
|
||||
const url = 'https://jsonplaceholder.typicode.com/posts';
|
||||
// Add your code below this line
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', url, true);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 201){
|
||||
const serverResponse = JSON.parse(xhr.response);
|
||||
document.getElementsByClassName('message')[0].textContent = serverResponse.userName + serverResponse.suffix;
|
||||
}
|
||||
};
|
||||
const body = JSON.stringify({ userName: userName, suffix: ' loves cats!' });
|
||||
xhr.send(body);
|
||||
// Add your code above this line
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Friends</h1>
|
||||
<p class="message">
|
||||
Reply from Server will be here
|
||||
</p>
|
||||
<p>
|
||||
<label for="name">Your name:
|
||||
<input type="text" id="name"/>
|
||||
</label>
|
||||
<button id="sendMessage">
|
||||
Send Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,171 @@
|
||||
---
|
||||
id: 587d7fae367417b2b2512be7
|
||||
title: Pre-filter JSON to Get the Data You Need
|
||||
challengeType: 6
|
||||
forumTopicId: 18257
|
||||
dashedName: pre-filter-json-to-get-the-data-you-need
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
If you don't want to render every cat photo you get from the freeCodeCamp Cat Photo API, you can pre-filter the JSON before looping through it.
|
||||
|
||||
Given that the JSON data is stored in an array, you can use the `filter` method to filter out the cat whose "id" key has a value of 1.
|
||||
|
||||
Here's the code to do this:
|
||||
|
||||
```js
|
||||
json = json.filter(function(val) {
|
||||
return (val.id !== 1);
|
||||
});
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add code to `filter` the json data to remove the cat with the "id" value of 1.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your code should use the `filter` method.
|
||||
|
||||
```js
|
||||
assert(code.match(/json\.filter/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json', true);
|
||||
req.send();
|
||||
req.onload=function(){
|
||||
let json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
json.forEach(function(val) {
|
||||
html += "<div class = 'cat'>"
|
||||
|
||||
html += "<img src = '" + val.imageLink + "' " + "alt='" + val.altText + "'>"
|
||||
|
||||
html += "</div>"
|
||||
});
|
||||
document.getElementsByClassName('message')[0].innerHTML = html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json', true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
let json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
// Add your code below this line
|
||||
json = json.filter(function(val) {
|
||||
return (val.id !== 1);
|
||||
});
|
||||
|
||||
// Add your code above this line
|
||||
json.forEach(function(val) {
|
||||
html += "<div class = 'cat'>"
|
||||
|
||||
html += "<img src = '" + val.imageLink + "' " + "alt='" + val.altText + "'>"
|
||||
|
||||
html += "</div>"
|
||||
});
|
||||
document.getElementsByClassName('message')[0].innerHTML = html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
@ -0,0 +1,161 @@
|
||||
---
|
||||
id: 587d7fae367417b2b2512be6
|
||||
title: Render Images from Data Sources
|
||||
challengeType: 6
|
||||
forumTopicId: 18265
|
||||
dashedName: render-images-from-data-sources
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The last few challenges showed that each object in the JSON array contains an `imageLink` key with a value that is the URL of a cat's image.
|
||||
|
||||
When you're looping through these objects, you can use this `imageLink` property to display this image in an `img` element.
|
||||
|
||||
Here's the code that does this:
|
||||
|
||||
`html += "<img src = '" + val.imageLink + "' " + "alt='" + val.altText + "'>";`
|
||||
|
||||
# --instructions--
|
||||
|
||||
Add code to use the `imageLink` and `altText` properties in an `img` tag.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should use the `imageLink` property to display the images.
|
||||
|
||||
```js
|
||||
assert(code.match(/val\.imageLink/g));
|
||||
```
|
||||
|
||||
You should use the `altText` for the alt attribute values of the images.
|
||||
|
||||
```js
|
||||
assert(code.match(/val\.altText/g));
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req=new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json',true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
json.forEach(function(val) {
|
||||
html += "<div class = 'cat'>";
|
||||
// Add your code below this line
|
||||
|
||||
|
||||
// Add your code above this line
|
||||
html += "</div><br>";
|
||||
});
|
||||
document.getElementsByClassName('message')[0].innerHTML=html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message box">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```html
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function(){
|
||||
document.getElementById('getMessage').onclick = function(){
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET",'/json/cats.json',true);
|
||||
req.send();
|
||||
req.onload = function(){
|
||||
const json = JSON.parse(req.responseText);
|
||||
let html = "";
|
||||
json.forEach(function(val) {
|
||||
html += "<div class = 'cat'>";
|
||||
// Add your code below this line
|
||||
html += "<img src = '" + val.imageLink + "' " + "alt='" + val.altText + "'>";
|
||||
// Add your code above this line
|
||||
html += "</div><br>";
|
||||
});
|
||||
document.getElementsByClassName('message')[0].innerHTML = html;
|
||||
};
|
||||
};
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
text-align: center;
|
||||
font-family: "Helvetica", sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
background-color: #eee;
|
||||
padding: 20px 5px;
|
||||
}
|
||||
button {
|
||||
color: white;
|
||||
background-color: #4791d0;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #4791d0;
|
||||
padding: 5px 10px 8px 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #0F5897;
|
||||
border: 1px solid #0F5897;
|
||||
}
|
||||
</style>
|
||||
<h1>Cat Photo Finder</h1>
|
||||
<p class="message">
|
||||
The message will go here
|
||||
</p>
|
||||
<p>
|
||||
<button id="getMessage">
|
||||
Get Message
|
||||
</button>
|
||||
</p>
|
||||
```
|
Reference in New Issue
Block a user