Add exercise 8

This commit is contained in:
Oystein Kristoffer Tveit 2020-10-27 02:30:35 +01:00
parent 61aba5e9e4
commit b335ec2b16
6 changed files with 427 additions and 0 deletions

View File

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

View File

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

View File

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

View File

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

46
Exercise 8/questions.txt Normal file
View File

@ -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:

17
Exercise 8/taxForms.js Normal file
View File

@ -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
}
];