Add exercise 8
This commit is contained in:
parent
61aba5e9e4
commit
b335ec2b16
|
@ -0,0 +1,187 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Tax forms: Bar chart with lines</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script src="taxForms.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<canvas id="chart" width="700" height="550"></canvas>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('chart');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
/* Draw a line from (fromX, fromY) to (toX, toY) */
|
||||||
|
function drawLine(fromX, fromY, toX, toY) {
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(toX, toY);
|
||||||
|
context.lineTo(fromX, fromY);
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text (string) on (x, y) */
|
||||||
|
function drawText(text, x, y) {
|
||||||
|
context.fillStyle = 'black';
|
||||||
|
context.fillText(text, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text and with a line to its right */
|
||||||
|
function drawLineWithText(text, fromX, fromY, toX, toY) {
|
||||||
|
drawText(text, fromX - 50, fromY + 10);
|
||||||
|
drawLine(fromX, fromY, toX, toY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert your code here. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw lines on the y axis of the canvas
|
||||||
|
*
|
||||||
|
* @param {number} n - Number of lines to draw
|
||||||
|
* @param {number} step - Number to add to y axis
|
||||||
|
*/
|
||||||
|
const drawNLines = (n, step) => {
|
||||||
|
for (let i = 1; i <= n; i++) {
|
||||||
|
const y = canvas.height * (n - i + 1 ) / (n+1);
|
||||||
|
const text = step * i;
|
||||||
|
drawLineWithText(text, 50, y, canvas.width - 100, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a rectangle onto the canvas
|
||||||
|
*
|
||||||
|
* @param {number} x - x value of the upper left corner of the rectangle
|
||||||
|
* @param {number} y - y value of the upper left corner of the rectangle
|
||||||
|
* @param {number} width - Width of the rectangle
|
||||||
|
* @param {number} height - Height of the rectangle (DOWNWARDS)
|
||||||
|
* @param {string} color - Color of the rectangle
|
||||||
|
*/
|
||||||
|
const drawRectangle = (x, y, width, height, color='red') => {
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.fillRect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cycle a list of colors
|
||||||
|
*
|
||||||
|
* @generator
|
||||||
|
*
|
||||||
|
* @param {string[]} colors - List of colors to cycle
|
||||||
|
* @yields {string} A color
|
||||||
|
*/
|
||||||
|
function* colorCycler(colors) {
|
||||||
|
let i = 0;
|
||||||
|
while (true) {
|
||||||
|
yield colors[i];
|
||||||
|
i = (i + 1) % colors.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a legend entry on the canvas
|
||||||
|
*
|
||||||
|
* @param {string[]} properties - An array of labels
|
||||||
|
* @param {[string[]} colorList - An array of colors to cycle when making labels
|
||||||
|
*/
|
||||||
|
const drawLabels = (properties, colorList) => {
|
||||||
|
const colors = colorCycler(colorList);
|
||||||
|
|
||||||
|
const drawLabel = (text, color, y) => {
|
||||||
|
drawText(text, canvas.width-45, y + 15)
|
||||||
|
drawRectangle(canvas.width - 90, y, 40, 20, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
const yOffset = canvas.height / 12
|
||||||
|
for (i in properties) {
|
||||||
|
drawLabel(properties[i], colors.next().value, yOffset+30*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a subset of bars on the canvas
|
||||||
|
*
|
||||||
|
* param {{
|
||||||
|
* x: number,
|
||||||
|
* width: number,
|
||||||
|
* adjustY: {val: number}=>number,
|
||||||
|
* object: Object.<string, number>,
|
||||||
|
* sep: number,
|
||||||
|
* colorList: string[]
|
||||||
|
* }} config -
|
||||||
|
* x: x value of where to start drawing bars
|
||||||
|
* width: Width of all the bars to draw collected
|
||||||
|
* adjustY: A function to adjust the y value of each bar to the upper left corner
|
||||||
|
* object: The object containing the values to draw
|
||||||
|
* sep: The amount of pixels between each bar
|
||||||
|
* colorList: A list of colors to cycle when creating bars
|
||||||
|
*/
|
||||||
|
const drawBars = ({x, width, adjustY, object, sep, colorList}) => {
|
||||||
|
const colors = colorCycler(colorList);
|
||||||
|
const values = Object.values(object)
|
||||||
|
|
||||||
|
const drawBar = (value, x) => {
|
||||||
|
const y = adjustY(value);
|
||||||
|
const localWidth = width / (values.length) - sep;
|
||||||
|
const localHeight = canvas.height - y;
|
||||||
|
drawRectangle(x, y, localWidth, localHeight, colors.next().value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i=0; i<values.length; i++) {
|
||||||
|
const xOffset = x + i * (sep + width / (values.length));
|
||||||
|
drawBar(values[i], xOffset);
|
||||||
|
}
|
||||||
|
colors.return();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw an array of objects as a diagram onto the canvas
|
||||||
|
*
|
||||||
|
* @param {Array.<Object.<string, number>>} data - An array of objects with graphable properties
|
||||||
|
* @param {string[]} colorList - An array of colors to cycle when drawing bars
|
||||||
|
* @param {{val: number}=>number} adjustY - A function to adjust the y value of
|
||||||
|
* each bar to the upper left corner
|
||||||
|
*/
|
||||||
|
const drawColumnSet = (data, colorList, adjustY) => {
|
||||||
|
const lineWidth = canvas.width - 150;
|
||||||
|
const columnSetWidth = lineWidth / (2 * data.length + 1) - data.length + 1;
|
||||||
|
const initialXOffset = 50 + columnSetWidth;
|
||||||
|
const xOffset = 2*columnSetWidth;
|
||||||
|
|
||||||
|
for (i in data) {
|
||||||
|
drawBars({
|
||||||
|
x: initialXOffset + i*xOffset,
|
||||||
|
width: columnSetWidth,
|
||||||
|
adjustY: adjustY,
|
||||||
|
object: data[i],
|
||||||
|
sep: 5,
|
||||||
|
colorList: colorList
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a bar chart diagram
|
||||||
|
*
|
||||||
|
* @param {Array.<Object.<string, number>>} data - An array of objects with graphable properties
|
||||||
|
* @param {number} range - The upper range of the graph (the top line)
|
||||||
|
* @param {number} step - The number to increase by for every unit on the axis
|
||||||
|
*/
|
||||||
|
const drawDiagram = (data, range, step) => {
|
||||||
|
drawNLines(range/step, step);
|
||||||
|
|
||||||
|
const colorList = ['red', 'blue'];
|
||||||
|
drawLabels(Object.getOwnPropertyNames(data[0]), colorList);
|
||||||
|
|
||||||
|
const adjustY = val => canvas.height * ( 1 - val / (step * (range/step + 1)));
|
||||||
|
drawColumnSet(data, colorList, adjustY);
|
||||||
|
}
|
||||||
|
|
||||||
|
const taxData = taxForms;
|
||||||
|
taxData.forEach(form => delete form.realName);
|
||||||
|
drawDiagram(taxData, 1000000, 100000);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,109 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Tax forms: Bar chart with lines</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script src="taxForms.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<canvas id="chart" width="700" height="550"></canvas>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('chart');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
/* Draw a line from (fromX, fromY) to (toX, toY) */
|
||||||
|
function drawLine(fromX, fromY, toX, toY) {
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(toX, toY);
|
||||||
|
context.lineTo(fromX, fromY);
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text (string) on (x, y) */
|
||||||
|
function drawText(text, x, y) {
|
||||||
|
context.fillStyle = 'black';
|
||||||
|
context.fillText(text, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text and with a line to its right */
|
||||||
|
function drawLineWithText(text, fromX, fromY, toX, toY) {
|
||||||
|
drawText(text, fromX - 50, fromY + 10);
|
||||||
|
drawLine(fromX, fromY, toX, toY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert your code here. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw lines on the y axis of the canvas
|
||||||
|
*
|
||||||
|
* @param {number} n - Number of lines to draw
|
||||||
|
* @param {number} step - Number to add to y axis
|
||||||
|
*/
|
||||||
|
const drawNLines = (n, step) => {
|
||||||
|
for (let i = 1; i <= n; i++) {
|
||||||
|
const y = canvas.height * (n - i + 1 ) / (n+1);
|
||||||
|
const text = step * i;
|
||||||
|
drawLineWithText(text, 50, y, canvas.width - 100, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws a rectangle onto the canvas
|
||||||
|
*
|
||||||
|
* @param {number} x - x value of the upper left corner of the rectangle
|
||||||
|
* @param {number} y - y value of the upper left corner of the rectangle
|
||||||
|
* @param {number} width - Width of the rectangle
|
||||||
|
* @param {number} height - Height of the rectangle (DOWNWARDS)
|
||||||
|
* @param {string} color - Color of the rectangle
|
||||||
|
*/
|
||||||
|
const drawRectangle = (x, y, width, height, color='red') => {
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.fillRect(x, y, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cycle a list of colors
|
||||||
|
*
|
||||||
|
* @generator
|
||||||
|
*
|
||||||
|
* @param {string[]} colors - List of colors to cycle
|
||||||
|
* @yields {string} A color
|
||||||
|
*/
|
||||||
|
function* colorCycler(colors) {
|
||||||
|
let i = 0;
|
||||||
|
while (true) {
|
||||||
|
yield colors[i];
|
||||||
|
i = (i + 1) % colors.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a legend entry on the canvas
|
||||||
|
*
|
||||||
|
* @param {string[]} properties - An array of labels
|
||||||
|
* @param {[string[]} colorList - An array of colors to cycle when making labels
|
||||||
|
*/
|
||||||
|
const drawLabels = (properties, colorList) => {
|
||||||
|
const colors = colorCycler(colorList);
|
||||||
|
|
||||||
|
const drawLabel = (text, color, y) => {
|
||||||
|
drawText(text, canvas.width-45, y + 15)
|
||||||
|
drawRectangle(canvas.width - 90, y, 40, 20, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
const yOffset = canvas.height / 12
|
||||||
|
for (i in properties) {
|
||||||
|
drawLabel(properties[i], colors.next().value, yOffset+30*i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawNLines(10, 100000);
|
||||||
|
const taxData = taxForms;
|
||||||
|
taxData.forEach(form => delete form.realName);
|
||||||
|
drawLabels(Object.getOwnPropertyNames(taxData[0]), ['red', 'blue']);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,55 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Tax forms: Bar chart with lines</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script src="taxForms.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<canvas id="chart" width="700" height="550"></canvas>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const canvas = document.getElementById('chart');
|
||||||
|
const context = canvas.getContext('2d');
|
||||||
|
|
||||||
|
/* Draw a line from (fromX, fromY) to (toX, toY) */
|
||||||
|
function drawLine(fromX, fromY, toX, toY) {
|
||||||
|
context.beginPath();
|
||||||
|
context.moveTo(toX, toY);
|
||||||
|
context.lineTo(fromX, fromY);
|
||||||
|
context.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text (string) on (x, y) */
|
||||||
|
function drawText(text, x, y) {
|
||||||
|
context.fillStyle = 'black';
|
||||||
|
context.fillText(text, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draw a text and with a line to its right */
|
||||||
|
function drawLineWithText(text, fromX, fromY, toX, toY) {
|
||||||
|
drawText(text, fromX - 50, fromY + 10);
|
||||||
|
drawLine(fromX, fromY, toX, toY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert your code here. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw lines on the y axis of the canvas
|
||||||
|
*
|
||||||
|
* @param {number} n - Number of lines to draw
|
||||||
|
*/
|
||||||
|
const drawNLines = (n) => {
|
||||||
|
for (let i = 1; i <= n; i++) {
|
||||||
|
const y = canvas.height * (n - i + 0.5) / n;
|
||||||
|
const text = 100000 * i;
|
||||||
|
drawLineWithText(text, 50, y, canvas.width, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawNLines(10);
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Income greather than 500 000</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<script src="taxForms.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
console.log(taxForms.filter(form => form.income > 500000));
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Questions
|
||||||
|
|
||||||
|
1. When calling `getContext('2d')` on a Canvas element, it will return a drawing context (i.e. the type of canvas) - in this case a two-dimensional context. How can we get a three-dimensional context instead?
|
||||||
|
|
||||||
|
You could use any version of WebGL. Webgl is an API for rendering graphics on the web, with the help of things like hardware acceleration and compiled function libraries which will run a lot faster than interpreting everything as javascript. Most modern browsers have an implementation of WebGL.
|
||||||
|
|
||||||
|
Example of usage:
|
||||||
|
```javascript
|
||||||
|
const ctx = canvas.getContext('webgl');
|
||||||
|
```
|
||||||
|
|
||||||
|
2. How would you create a blue circle using the Canvas element? Explain with words or code.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const drawCircle = (x, y, radius) => {
|
||||||
|
context.beginPath();
|
||||||
|
context.fillStyle('blue');
|
||||||
|
context.arc(x,y,0, Math.PI*2);
|
||||||
|
context.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawCircle();
|
||||||
|
```
|
||||||
|
|
||||||
|
3. What is a more terse (also known as shorter) way of writing the loop in the following usingthe Array.filter method?
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const countries = ['Norway', 'Sweden', 'Denmark', 'New Zealand'];
|
||||||
|
const countriesStartingWithN = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < countries.length; i++) {
|
||||||
|
let country = countries[i];
|
||||||
|
if (country.startsWith('N')) {
|
||||||
|
countriesStartingWithN.push(country);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
```javascript
|
||||||
|
const countries = ['Norway', 'Sweden', 'Denmark', 'New Zealand'];
|
||||||
|
|
||||||
|
const countriesStartingWithN = countries.filter(
|
||||||
|
country => country.startsWith('n')
|
||||||
|
);
|
||||||
|
```
|
||||||
|
|
||||||
|
[//]: # vim: set syntax=markdown:
|
|
@ -0,0 +1,17 @@
|
||||||
|
const taxForms = [
|
||||||
|
{
|
||||||
|
realName: "Bruce Wayne",
|
||||||
|
income: 750000,
|
||||||
|
wealth: 300000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
realName: "John Blake",
|
||||||
|
income: 440000,
|
||||||
|
wealth: 832000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
realName: "Selina Kyle",
|
||||||
|
income: 640000,
|
||||||
|
wealth: 432000
|
||||||
|
}
|
||||||
|
];
|
Loading…
Reference in New Issue