Code Examples for Reading 17
Download
You can also download a ZIP file containing this code.
After downloading and unpacking the ZIP file:
npm install
to install package dependencies;npm run
to see a list of the ways this code can be run.- For example, if
npm run
shows that there are scripts calledfoo
andbar
, you can run the code with eithernpm run foo
ornpm run bar
. - Two conventional script names are
test
andstart
. If the code includes one of those script names, then you can omitrun
and just saynpm test
ornpm start
.
- For example, if
draw.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Draw!</title>
<style>
#canvas {
border: 1px solid black;
}
div {
margin: 5px;
}
</style>
</head>
<body>
<div>
Color: <input type="text" id="colorTextbox" value="green">
</div>
<div>
Shape: <select id="shapeDropdown">
<option value="circle" selected>circle</option>
<option value="square">square</option>
</select>
<input type="checkbox" id="filledCheckbox" checked="true"> filled
</div>
<div>
Size: <input type="number" id="sizeTextbox" value="10" min="1" max="50" maxlength="2">
<input type="range" id="sizeSlider" value="10" min="1" max="50">
</div>
<div>
<button id="drawRandomlyButton">Draw Randomly</button>
<button id="clearButton">Clear</button>
</div>
<div>
<canvas id="canvas" width="200" height="300">
</canvas>
</div>
<script src="dist/draw-bundle.js"></script>
<script>
if ( ! document.body.classList.contains('codeLoaded')) {
alert('You may need to "npm install" and "npm run compile" first. If you did that, look in the browser console for errors.')
}
</script>
</body>
</html>
draw.ts
/* Copyright (c) 2021-25 MIT 6.031/6.102 course staff, all rights reserved.
* Redistribution of original or derived work requires permission of course staff.
*/
// this code is loaded into draw.html
/**
* @param tag HTML element tag
* @param id id attribute
* @returns element whose tag is `tag` and id attribute is `id`
* @throws error if no such element
*/
function getElementById<Tag extends keyof HTMLElementTagNameMap>(tag: Tag, id: string): HTMLElementTagNameMap[Tag] {
const element = document.querySelector<HTMLElementTagNameMap[Tag]>(`${tag}#${id}`);
if (!element) { throw new Error(`no element ${tag}#${id} found`); }
return element;
}
const drawRandomlyButton: HTMLButtonElement = getElementById('button', 'drawRandomlyButton');
const clearButton: HTMLButtonElement = getElementById('button', 'clearButton');
const canvasElement: HTMLCanvasElement = getElementById('canvas', 'canvas');
const colorTextbox: HTMLInputElement = getElementById('input', 'colorTextbox');
const shapeDropdown: HTMLSelectElement = getElementById('select', 'shapeDropdown');
const filledCheckbox: HTMLInputElement = getElementById('input', 'filledCheckbox');
const sizeTextbox: HTMLInputElement = getElementById('input', 'sizeTextbox');
const sizeSlider: HTMLInputElement = getElementById('input', 'sizeSlider');
canvasElement.addEventListener('click', (event:MouseEvent) => {
drawShape(event.offsetX, event.offsetY);
});
drawRandomlyButton.addEventListener('click', () => {
drawShape(canvasElement.width * Math.random(), canvasElement.height * Math.random());
// for (let i = 0; i < 1_000_000; ++i) {
// drawShape(canvasElement.width * Math.random(), canvasElement.height * Math.random());
// }
});
clearButton.addEventListener('click', clear);
// synchronize the size textbox and slider
sizeTextbox.addEventListener('input', () => {
sizeSlider.value = sizeTextbox.value;
});
sizeSlider.addEventListener('input', () => {
sizeTextbox.value = sizeSlider.value;
});
/**
* @returns color shown in the color textbox
*/
function getColor():string {
return colorTextbox.value;
}
/**
* @returns size shown in the size textbox
*/
function getSize():number {
return parseInt(sizeTextbox.value);
}
/**
* Draw a square filled with a random color.
* @param x x position of center of box centers
* @param y y position of center of box centers
*/
function drawShape(x: number, y: number):void {
console.log(`canvas width: ${canvasElement.width}`);
const canvas = canvasElement.getContext('2d');
if ( ! canvas ) throw new Error('unable to get canvas drawing context');
// save original context settings before we translate and change colors
canvas.save();
// move origin to (x,y)
canvas.translate(x, y);
// describe the shape, either a circle or a rectangle, centered on the origin
const size = getSize();
canvas.beginPath();
if (shapeDropdown.value === 'circle') {
canvas.arc(0, 0, size/2, 0, 2 * Math.PI);
} else {
canvas.rect(-size/2, -size/2, size, size)
}
// stroke the outline of the shape
canvas.strokeStyle = getColor();
canvas.lineWidth = 2;
canvas.stroke();
if (filledCheckbox.checked) {
// fill with a color
canvas.fillStyle = getColor();
canvas.fill();
}
// reset the origin and styles back to defaults
canvas.restore();
}
/**
* Clear the drawing area, filling it with white again.
*/
function clear() {
const context = canvasElement.getContext('2d');
if ( ! context ) throw new Error('unable to get canvas drawing context');
context.save();
context.fillStyle = 'white';
context.fillRect(0, 0, canvasElement.width, canvasElement.height);
context.restore();
}
document.body.classList.add('codeLoaded'); // used to remind about compiling first