Compare commits
10 Commits
assignment
...
master
Author | SHA1 | Date |
---|---|---|
Oystein Kristoffer Tveit | c18355e9e5 | |
Oystein Kristoffer Tveit | b335ec2b16 | |
Oystein Kristoffer Tveit | 61aba5e9e4 | |
Oystein Kristoffer Tveit | d6acf623c0 | |
Oystein Kristoffer Tveit | 0983b959ab | |
Oystein Kristoffer Tveit | 58ffcec09b | |
Oystein Kristoffer Tveit | 4581f41517 | |
Oystein Kristoffer Tveit | 1730241869 | |
Oystein Kristoffer Tveit | 92e6fa1297 | |
h7x4 | 1514d33f1c |
|
@ -0,0 +1,74 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>About</title>
|
||||||
|
<link rel="shortcut icon" href="img/favicon.svg" type="image/svg+xml">
|
||||||
|
<!-- Royalty free icon, source: https://pixabay.com/vectors/flat-design-symbol-icon-www-2126879/ -->
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<h1>Name: Øystein Tveit</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<h2>This is me</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<img
|
||||||
|
src="./img/html_joke.jpg"
|
||||||
|
alt="An html joke"
|
||||||
|
id="htmlJoke"
|
||||||
|
style="border-width: 6px;"
|
||||||
|
>
|
||||||
|
<!-- Increased to 6px assuming default border-width "medium" at 96dpi is about 4px, https://www.sitepoint.com/community/t/pixel-equivelant-of-border-width-thin-medium-thick/4225/2 -->
|
||||||
|
<!-- Source: http://funnygeekjokes.blogspot.com/2013/02/how-to-tell-html-from-html5-joke.html -->
|
||||||
|
|
||||||
|
<p>
|
||||||
|
I like programming. I've done it on a regular basis ever since a friend of mine introduced me to it in elementary school. I've been working a little bit with a lot of languages, but the ones I use on a regular basis would be Javascript running in Node.js, Dart + Flutter
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I've also written a bit of shellscript for UNIX based systems. But even though shellscript is theoretically a programming language, I wouldn't really call the shellscripts "programs". They're more like a thread sewing together programs that are already installed on the system in special ways to automate a certain workflow.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Even though I've done quite a bit of HTML, CSS and Javascript before, I'm looking forward to get a new perspective on the things I know, and learn things I didn't know. There's a lot of tips and tricks for every language out there, and even when you think you know it all, there will still be more to learn.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header>
|
||||||
|
<h2>Questions</h2>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
The server provides content and/or services to the client. In the case of services, it makes more sense for the server to be responsible for it because it's more cost efficient in terms of power and easier to maintain. It's also centralizes the content delivery, and this makes the content safer in many ways. In the case of the WWW, the server would be the webserver providing HTML documents, stylesheets, scripts and other assets. In many cases it would also be responsible for processing services and maybe content processing before delivery. However, the server is also the system's weak point. If the server shuts down for any reason, none of the clients will be able to use the system.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The client is the user's terminal or endpoint. The client requests services and content. It usually doesn't need to do a lot of heavy processing, and it's very dependent on the server to function. This means that it doesn't really matter how much processing power you have on your client, because the server handles most of it anyway.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
An IP address which is short for an Internet Protocol address is an identifier a computer can use to communicate with other computers on a computer network. It's often referred to as the computer's "name". As of today, the most normal types of IP address is IPv4 and IPv6. However, we are soon running out of IPv4 addresses for the internet, because there is only 2^32 or about 4.3 billon possible IPv4 combinations. For local networks however, IPv4 is still the most common protocol.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
DNS is a system where we mask IP addresses as URLs in order to make it easier for us to remember. For example, it's much easier to remember https://google.com rather than 172.217.14.228. In order for this to work, there exists a lot of DNS servers providing name resolution for URLs. Sometimes, a DNS server doesn't have the IP for a specific site. It will then ask another DNS server for the IP. Any person can make a DNS server, but some DNS servers are more commonly used and trusted than others. ISPs often run their own DNS servers. In some countries, this can be problematic because the government can remove certain domains and block access to DNS servers in other countries. Because the DNS servers are so critical for anyone to access the WWW, the servers are often known to be incredibly stable. Therefore, pinging a DNS server like 8.8.8.8 (Google's DNS server) can be a good indicator whether you are connected to the internet or not. If you don't recieve a response, it's probably not the DNS server that's down.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The internet is the computer network connecting computers all over the world. The World Wide Web however, is a term describing the vast amount of documents shared on web servers arond the world. We usually call these documents websites, which are usually read in programs called web browsers. It's usually described as an enourmus spiderweb where the different junctions connect to each other using links. But there's much more to the internet than just the web. Enourmus loads of types of different information using protocols like FTP, SSH, XMPP and proprietary protocols connecting to different servers also use the internet for communication. But it's not something that you can see in a web browser. For example, these days, whenever you send an SMS, it travels through the internet. But it's not linked anywhere on a website, and it's not something you can view in a web browser.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
HTML is a markup language, based on XML. It's used to classify specific parts of text in nodes with properties inside of a big node tree structure. A markup language is not the same as a programming language because it can't- and is not meant to be used to process and calculate arithmetic or logic. We say that it's not Turing complete. In the case of HTML in a web browser, calculation and processing is usually (but not necessarily) left to JavaScript, or the server (via languages like PHP).
|
||||||
|
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer>Created by: Øystein Tveit</footer>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,141 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Te</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="stylesheet" href="css/article.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<article>
|
||||||
|
<img id="cover" src="img/te.png" alt="Cover image" />
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Te</h1>
|
||||||
|
<p>Tekst: Offline/Thor Håkon "tepose" Bredesen</p>
|
||||||
|
<p>Publisert: <time datetime="2014-02-15">2 februar, 2014</time></p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<section id="intro">
|
||||||
|
<p>Du har neppe sett meg ta en slurk kaffe, for jeg liker ikke
|
||||||
|
kaffe. Te derimot, det liker jeg. La meg ta deg med på en kort og overfladisk
|
||||||
|
reise inn i teens verden.</p>
|
||||||
|
|
||||||
|
<p>Tedrikking står sterkt i mange av verdens kulturer. For flere
|
||||||
|
tusen år siden ble te brukt som medisin i Kina. I de seneste tiårene har
|
||||||
|
forskere startet å se på hva som gjør te bra. Te er også blitt en sosial drikk,
|
||||||
|
eller noe du koser deg med alene. For te har mange gode egenskaper som gjør det
|
||||||
|
til en sunn drikk, i tillegg til å smake godt.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<aside id="facts">
|
||||||
|
<ul>
|
||||||
|
<li>Det amerikanere kaller svart te kaller kineserne for rød te <sup>[<a href="#bib1">1</a>]</sup>.</li>
|
||||||
|
<li>Britene drikker omtrent 165 millioner kopper med te hver dag <sup>[<a href="#bib2">2</a>]</sup>.</li>
|
||||||
|
<li>Før 1800-tallet ble te brukt som en valuta i Siberia <sup>[<a href="#bib3">3</a>]</sup>.</li>
|
||||||
|
</ul>
|
||||||
|
</aside>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Te er ikke bare te</h2>
|
||||||
|
<p>Te er ikke te, eller, te er te, men ikke alt du tror er te er
|
||||||
|
te. Den harde sannheten er at te kommer fra planten Camellia sinensis, og gjør
|
||||||
|
den ikke det er det ikke te. «Hva med frukt- og urtete?», tenker du kanskje.
|
||||||
|
Sorry kompis, det er kun infusjon, tørkede frukter og urter blandet med varmt
|
||||||
|
vann!</p>
|
||||||
|
|
||||||
|
<p>Men før du hopper på toget mitt og proklamerer alt som ikke
|
||||||
|
kommer fra den nevnte planten som «ikke ordentlig te», la meg fortelle deg at
|
||||||
|
også te er infusjon, siden det er blandet med vann, men det kommer i hvert fall
|
||||||
|
fra teplanten. Fra Camellia sinensis får vi grønn, hvit, oolong og svart te. De
|
||||||
|
har vidt forskjellige smaker og utseende, til tross for at de kommer fra samme
|
||||||
|
plante. Forskjellen ligger i hvordan de blir behandlet etter at de er høstet,
|
||||||
|
og også når de blir høstet.</p>
|
||||||
|
|
||||||
|
<p>Når det lages svart te blir tebladene delvis tørket, rullet,
|
||||||
|
fermentert (gjæret) og så tørket helt. Grønn te blir først dampet for at den
|
||||||
|
ikke skal gjære, og så blir den rullet og tørket. Oolong te blir fremstilt som
|
||||||
|
sort te, men gjærer kortere. Hvit te plukkes kun to ganger i året, og blir kun
|
||||||
|
tørket. Det er også den dyreste tesorten av de fire.</p>
|
||||||
|
|
||||||
|
<p>Te deles inn i ulike kvaliteter. Den høyeste kvaliteten består
|
||||||
|
av hele blader. Når tebladene knuses, som gjøres for å lage posete, kalles teen
|
||||||
|
for broken. Den laveste kvaliteten av te kalles fannings og dust. Som navnet
|
||||||
|
tilsier er dette de skarve restene som ligger igjen etter at teen er blitt
|
||||||
|
sortert og knust. Teposer du kjøper i dagligvarebutikkene er som regel fannings
|
||||||
|
eller dust. Søsteren min, som er en ihugga tenerd, ser for seg denne kvaliteten
|
||||||
|
som oppsopet fra gulvet etter at teen som er verdt å drikke er blitt sortert.
|
||||||
|
Hun drikker ikke mye posete.</p>
|
||||||
|
|
||||||
|
<p>Det er verdt å merke at fannings av eksklusive teblader
|
||||||
|
riktignok kan være både dyrere og mer smaksrike enn hele blader av billige
|
||||||
|
tevarianter.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Tehverdagen</h2>
|
||||||
|
<p> Behandlingen tebladene gjennomgår etter høsting påvirker smak
|
||||||
|
og utseende, men det påvirker også nivået av koffein og hvilke helseeffekter
|
||||||
|
teen har. Svart te har mest koffein i seg, omtrent halvparten av en normal
|
||||||
|
kaffekopp. Grønn te har halvparten så mye koffein som svart te, og hvit te har
|
||||||
|
nesten ikke noe koffein i seg. Svart te og oolong er oppkvikkende, mens hvit og
|
||||||
|
grønn te er beroligende. Om du har en treg fordøyelse kan både grønn te og
|
||||||
|
svart te sette fortgang i systemet. Te kan virke mot karies og munnsykdommer,
|
||||||
|
det gjelder dog bare om du ikke drikker det med sukker eller honning. Sist, men
|
||||||
|
ikke minst, senker inntak av te blodtrykket.</p>
|
||||||
|
|
||||||
|
<p> Jeg spurte søsteren min om hennes tevaner for å få et inntrykk
|
||||||
|
av hva som passer å drikke når. Her er en kort oppsummering av hennes
|
||||||
|
tehverdag, fortalt av henne.</p>
|
||||||
|
|
||||||
|
<blockquote>– Jeg drikker svart te om morgenen, litt for å våkne, men også
|
||||||
|
fordi jeg liker kraftigere smaker tidlig på dagen, og litt fordi jeg som folk
|
||||||
|
flest er et vanedyr. Denne teen smaker godt til brødmat, knekkebrød, scones, og
|
||||||
|
den slags. Det smaker også godt til en cookie, det kan jeg ikke nekte for.
|
||||||
|
Favoritten er masala chai, eller chai te som de fleste kaller det. Det er en
|
||||||
|
svart te som er tilsatt krydder. Chai er ordet for te på mange språk, blant
|
||||||
|
annet arabisk, bulgarsk, hindu, russisk og urdu. Så når folk ber om chai te ber
|
||||||
|
de om te te. Tantebarna mine kaller dette for pepperkakete, for det er det det
|
||||||
|
lukter som. I Kina sier de forresten cha. Chai er et kinesisk etternavn, men
|
||||||
|
det er en digresjon. Når jeg drikker svart te bruker jeg honning og suketter,
|
||||||
|
som skaper søthet og forsterker smaken på hver sin måte. Jeg liker også å ha
|
||||||
|
melk i for å få en rundere smak. Om kvelden drikker jeg som oftest grønn
|
||||||
|
smaksatt te, som bidrar til ro. Salte ting er overraskende godt til grønn te,
|
||||||
|
prøv det til popcorn eller potetgull.</blockquote>
|
||||||
|
|
||||||
|
<p>Ulike typer te skal også tilberedes forskjellig for å få den
|
||||||
|
beste smaken. Her skal du få noen generelle råd, kjære leser. Svart te er i
|
||||||
|
grunn den eneste teen som skal trekkes i kokt vann. Oolong skal trekkes på 90
|
||||||
|
grader, mens hvit og grønn te skal trekke på 80 grader. Hvor lenge teen skal
|
||||||
|
trakte varierer også fra tetype til tetype. Om du ønsker en sterkere smak, ha
|
||||||
|
mer te i koppen, ikke la den trekke lengre. Om den trekker for lenge blir den
|
||||||
|
bitter, og det er ikke godt. For teer som allerede er litt bitre, slik som
|
||||||
|
svart te, er det godt med noe søtt oppi, honning, sukketter eller sukker.
|
||||||
|
Bitter te passer godt til søte kaker, ellers blir det for mye søtt.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<h2>Verdens beste infusjon</h2>
|
||||||
|
<p>For å ikke ekskludere te som ikke er te vier jeg litt
|
||||||
|
spalteplass til rooibush, urte- og fruktte også. Rooibush kommer fra en plante
|
||||||
|
som vokser i Afrika. Den brukes på samme måte som te fra Camellia Sinensis, og
|
||||||
|
er svært rik på antioksidanter. I motsetning til te blir den ikke besk ved å
|
||||||
|
trekke for lenge.</p>
|
||||||
|
|
||||||
|
<p>Om du liker tesmaken, og du liker lakris, anbefaler jeg deg å
|
||||||
|
kjøpe urteblandingen Frisk Mint fra Te og Kaffehuset i Trondheim. Jeg skal ikke
|
||||||
|
skryte så mye at du blir skuffet når du drikker den, men om den er tilberedet
|
||||||
|
riktig er det kanskje verdens beste infusjon (helt objektivt altså). Jeg smilte
|
||||||
|
første gang jeg drakk den, og jeg smiler fortsatt!</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="bibliography">
|
||||||
|
<h2>Referanser</h2>
|
||||||
|
<ol>
|
||||||
|
<li id='bib1'>Goodwin, L., Red Tea. Tilgjengelig fra: <a href="http://coffeetea.about.com/od/Tea-Glossary/g/Red-Tea.htm" target="_blank">about.com</a> [Åpnet 2016–5].</li>
|
||||||
|
<li id='bib2'>Ukjent, UK Tea & Infusions Association - Tea Glossary and FAQ’s. Tilgjengelig fra: <a href="https://www.tea.co.uk/tea-faqs" target="_blank">tea.co.uk</a> [Åpnet 2016–5].</li>
|
||||||
|
<li id='bib3'>Bresset, K., Tea Money Of China. Tilgjengelig fra: <a href="http://www.charm.ru/coins/misc/teamoney.shtml" target="_blank">Charm.ru</a> [Åpnet 2016–5a].</li>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
</article>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,62 @@
|
||||||
|
:root{
|
||||||
|
/*
|
||||||
|
The average character is more narrow than 0 using these fonts.
|
||||||
|
I ended up picking 60ch based on testing different sizes and
|
||||||
|
finding the word count of the longest and shortest line.
|
||||||
|
*/
|
||||||
|
--articleWidth: 60ch
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Georgia, Verdana;
|
||||||
|
background: lightgray;
|
||||||
|
color: #323232;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
article {
|
||||||
|
width: var(--articleWidth);
|
||||||
|
margin: auto;
|
||||||
|
font-size: 22px
|
||||||
|
}
|
||||||
|
|
||||||
|
#cover {
|
||||||
|
width: var(--articleWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3em;
|
||||||
|
margin-block-end: 0em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will remove the space between the title and the byline entirely
|
||||||
|
header > p:first-of-type {
|
||||||
|
margin-block-start: 0em;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
header {
|
||||||
|
border-bottom: solid 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.8em;
|
||||||
|
}
|
||||||
|
|
||||||
|
p, blockquote, ul, ol {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#facts {
|
||||||
|
margin: 1em 0em 1em 1em;
|
||||||
|
width: 50%;
|
||||||
|
border: 1px dashed;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#facts > ul {
|
||||||
|
list-style-image: url('../img/cup-icon.svg');
|
||||||
|
line-height: 1.5em;
|
||||||
|
padding-left: 1.5em;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
body {
|
||||||
|
background: #EEEEEE
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
font-family: 'Times New Roman', Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-family: 'Noto Serif', Helvetica, Arial;
|
||||||
|
}
|
||||||
|
|
||||||
|
#htmlJoke {
|
||||||
|
max-width: 150px;
|
||||||
|
border: solid;
|
||||||
|
border-color: red;
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="12" height="12" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1600 640q0-80-56-136t-136-56h-64v384h64q80 0 136-56t56-136zm-1664 768h1792q0 106-75 181t-181 75h-1280q-106 0-181-75t-75-181zm1856-768q0 159-112.5 271.5t-271.5 112.5h-64v32q0 92-66 158t-158 66h-704q-92 0-158-66t-66-158v-736q0-26 19-45t45-19h1152q159 0 271.5 112.5t112.5 271.5z"/></svg>
|
After Width: | Height: | Size: 382 B |
|
@ -0,0 +1,125 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||||
|
sodipodi:docname="favicon.svg"
|
||||||
|
id="svg18"
|
||||||
|
viewBox="0 0 322.93549 322.93549"
|
||||||
|
version="1.1"
|
||||||
|
height="322.93549"
|
||||||
|
width="322.93549">
|
||||||
|
<metadata
|
||||||
|
id="metadata24">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs22" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:current-layer="svg18"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="48"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:cy="170.2036"
|
||||||
|
inkscape:cx="170.01564"
|
||||||
|
inkscape:zoom="1.294"
|
||||||
|
showgrid="false"
|
||||||
|
id="namedview20"
|
||||||
|
inkscape:window-height="1004"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
guidetolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
objecttolerance="10"
|
||||||
|
borderopacity="1"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
inkscape:document-rotation="0" />
|
||||||
|
<circle
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#009900;stroke-width:23.0416;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
cx="161.46774"
|
||||||
|
cy="161.46774"
|
||||||
|
r="149.94695"
|
||||||
|
fill="none"
|
||||||
|
stroke="#555555"
|
||||||
|
stroke-width="14.6177"
|
||||||
|
id="circle2" />
|
||||||
|
<path
|
||||||
|
d="m 113.39588,102.28858 c -4.8345,-0.0773 -8.30498,4.63035 -6.79409,9.22346 l 44.51155,135.6218 c 1.88088,5.695 9.57132,6.56851 12.68235,1.44131 l 20.35486,-33.58605 29.29021,29.2895 c 2.74441,2.7435 7.19254,2.7435 9.93744,0 l 24.89808,-24.88402 c 2.74301,-2.7442 2.74301,-7.19254 0,-9.93674 l -29.2902,-29.29021 33.54459,-20.32745 c 5.12761,-3.11103 4.25368,-10.80112 -1.44118,-12.68235 L 115.4677,102.64627 c -0.66894,-0.22487 -1.36761,-0.34434 -2.07252,-0.35839 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path4" />
|
||||||
|
<path
|
||||||
|
d="m 121.44225,56.610477 a 4.9457436,4.9457436 0 0 0 -4.87252,5.00983 v 19.95641 a 4.947995,4.947995 0 0 0 9.89599,0 v -19.95641 a 4.9457436,4.9457436 0 0 0 -5.02347,-5.00983 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path6" />
|
||||||
|
<path
|
||||||
|
d="m 161.13301,73.476237 a 4.9457436,4.9457436 0 0 0 -3.40394,1.49613 l -16.45676,16.45677 a 4.9457436,4.9457436 0 1 0 6.99992,6.98664 L 164.729,81.959007 a 4.9457436,4.9457436 0 0 0 -3.59606,-8.48277 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path8" />
|
||||||
|
<path
|
||||||
|
d="m 65.342519,112.82968 a 4.9457436,4.9457436 0 1 0 0,9.88263 h 25.66617 a 4.9457436,4.9457436 0 1 0 0,-9.88263 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path10" />
|
||||||
|
<path
|
||||||
|
d="m 81.744469,73.476237 a 4.9457436,4.9457436 0 0 0 -3.44504,8.48277 l 14.20589,14.20519 a 4.9457436,4.9457436 0 1 0 6.99992,-6.98594 l -14.20589,-14.20589 a 4.9457436,4.9457436 0 0 0 -3.55488,-1.49613 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path12" />
|
||||||
|
<path
|
||||||
|
d="m 98.673479,136.0201 a 4.9457436,4.9457436 0 0 0 -3.40394,1.49613 l -16.51158,16.51158 a 4.9457436,4.9457436 0 1 0 6.98622,7 l 16.525641,-16.52564 a 4.9457436,4.9457436 0 0 0 -3.596061,-8.48207 z"
|
||||||
|
color="#000000"
|
||||||
|
color-rendering="auto"
|
||||||
|
fill="#555555"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
image-rendering="auto"
|
||||||
|
shape-rendering="auto"
|
||||||
|
solid-color="#000000"
|
||||||
|
style="text-indent:0;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;text-transform:none;white-space:normal;isolation:auto;mix-blend-mode:normal;fill:#009900;fill-opacity:1;stroke-width:7.0274"
|
||||||
|
id="path14" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 1.3 MiB |
|
@ -0,0 +1,49 @@
|
||||||
|
# Questions
|
||||||
|
|
||||||
|
## 1. Why does inline style CSS override rules defined in style elements and external stylesheets?
|
||||||
|
|
||||||
|
inline style CSS overrides external stylesheets because it's the most specific ruleset. Rules from external stylesheets might match the object, but if you know that this specific element should be styled differently, it could be written explicitly in the tag options of the element. However, in this case it would be best practise to use an ID and specify the rules in a stylesheet.
|
||||||
|
|
||||||
|
## 2. Give a brief example of when to use ID ( #id ) and when to use classes ( .class ) in CSS.
|
||||||
|
|
||||||
|
ID is used when there's a piece that only occurs once on the page. A class is used for common parts that will occur several times. Let's take youtube as an example. The search bar, the logo in the header and the video is something that will only occur once. Those are good opportunities to use IDs. Comments and suggested videos however, will show up multiple times. Using classes is a good way to reach these pieces with JS and CSS. Sometimes, people confuse tags with classes. Tags are used in the same way as classes to mark several elements of the same type. But it is good practise to only use the standard HTML tags defined by WHATWG and use classes for any custom recurring parts that you have defined yourself. It makes it easier to define objects with several classes at once, and it's what's expected by most browsers (even though most browsers are able to handle custom tags too.)
|
||||||
|
|
||||||
|
## 3. What does RGBA mean and what colors can you express with it?
|
||||||
|
|
||||||
|
RGBA is an acronym meaning "Red, Green, Blue, Alpha" where the three first represent subpixel brightness values and the fourth represents opacity. With the RGB colors, you can express most colors that anyone can think of on the top of their head. Usually, we express them with a bitdepth of 8, meaning you can specify each individual color value to a range of 2^8 values -> between 0 and 255. With the alpha channel added, we can also specify how transparent the color should be. This is especially useful for things like non-square icons, watermarks and in web development - see-through floating windows. An example of a color that could be expressed with RGBA would be a 50% seethrough yellow, RGB(255,255,0, 127), or with alternative hexadecimal syntax -> #FFFF007f.
|
||||||
|
|
||||||
|
Note that the actual amount of colors you can express with RGBA depends on several other factors like your monitor, the colorspace, the brightness in the room you're sitting.
|
||||||
|
|
||||||
|
![Diagram showing hue along the x axis and opacity along the y axis](https://upload.wikimedia.org/wikipedia/commons/0/0b/RGBA_comp.png)
|
||||||
|
|
||||||
|
## 4. Why do we include CSS files inside the head element and not inside the body element?
|
||||||
|
|
||||||
|
We include the CSS into the head element in order to separate content and settings/metadata. Information like styling, scripts, and metadata should not be mixed with the content, and is therefore specified in the `<head>` before the `<body>`
|
||||||
|
|
||||||
|
## 5. What CSS selector matches all the p elements inside the article element in the following HTML?
|
||||||
|
|
||||||
|
```HTML
|
||||||
|
<p>This should not match.</p>
|
||||||
|
<article>
|
||||||
|
<h2>This should not match</h2>
|
||||||
|
<p>This should match.</p>
|
||||||
|
<p>This should also match.</p>
|
||||||
|
<p>Do not forget about this one!</p>
|
||||||
|
</article>
|
||||||
|
```
|
||||||
|
|
||||||
|
Here, we have two options. You could either do
|
||||||
|
|
||||||
|
```CSS
|
||||||
|
article p {}
|
||||||
|
```
|
||||||
|
|
||||||
|
which specifies all `<p>` elements inside the `<article>`.
|
||||||
|
|
||||||
|
The other option would be
|
||||||
|
|
||||||
|
```CSS
|
||||||
|
article > p {}
|
||||||
|
```
|
||||||
|
|
||||||
|
which would only specify `<p>` elements directly beneath the `<article>`. But since `<article>` has no `<p>` subchildren, both will work.
|
|
@ -0,0 +1,11 @@
|
||||||
|
1. The difference between `position: absolute;` and `position: fixed;` is that the absolute element is fixed onto the page itself, but the fixed element is fixed onto the "screen" or web browser so to say. If you scroll down, the fixed element won't move, but the absolute value will follow the page as any other unstyled element.
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
```CSS
|
||||||
|
element > anotherElement:nth-of-type(3n) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
[//]: # vim: set syntax=markdown:
|
|
@ -0,0 +1,34 @@
|
||||||
|
html, body{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Part 3 */
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
padding-bottom: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapper footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
padding: 20px 40px;
|
||||||
|
font-size: 20px;
|
||||||
|
color: white;
|
||||||
|
background-color: #404040C0;
|
||||||
|
margin-block-end: 0;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Part 4 */
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style-type: square;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul > ul > li:last-child {
|
||||||
|
font-weight: 900;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>A list apart</title>
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
<h1>This is a list</h1>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>HTML5</li>
|
||||||
|
<li>CSS</li>
|
||||||
|
<ul>
|
||||||
|
<li>LESS</li>
|
||||||
|
<li>Sass</li>
|
||||||
|
<li>SCSS</li>
|
||||||
|
</ul>
|
||||||
|
<li>JavaScript</li>
|
||||||
|
<ul>
|
||||||
|
<li>React</li>
|
||||||
|
<li>Node</li>
|
||||||
|
<li>Jquery</li>
|
||||||
|
<li>AngularJS</li>
|
||||||
|
<li>Backbone</li>
|
||||||
|
<li>Ember</li>
|
||||||
|
<li>Babel</li>
|
||||||
|
</ul>
|
||||||
|
</ul>
|
||||||
|
<footer>Here's some footer text</footer>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,133 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>IT2805</title>
|
||||||
|
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
html, body{
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
/* Part 1 */
|
||||||
|
|
||||||
|
.header{
|
||||||
|
font-family: sans-serif;
|
||||||
|
padding-top: 30px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box{
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #0060A3;
|
||||||
|
border-style: solid;
|
||||||
|
height: 400px;
|
||||||
|
|
||||||
|
margin: 0 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.one{
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #FAA21B;
|
||||||
|
border-style: solid;
|
||||||
|
|
||||||
|
margin-top: 25px;
|
||||||
|
margin-left: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.two{
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #FAA21B;
|
||||||
|
border-style: solid;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
margin-left: 25px;
|
||||||
|
position: relative;
|
||||||
|
top: 145px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.three{
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #FAA21B;
|
||||||
|
border-style: solid;
|
||||||
|
background-color: #fff;
|
||||||
|
|
||||||
|
margin-left: auto;
|
||||||
|
position: relative;
|
||||||
|
left: 50px;
|
||||||
|
bottom: 150px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.five{
|
||||||
|
bottom: 10px;
|
||||||
|
font-size: 35px;
|
||||||
|
font-family: sans-serif;
|
||||||
|
|
||||||
|
text-align: right;
|
||||||
|
margin-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.four{
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
border-width: 2px;
|
||||||
|
border-color: #FAA21B;
|
||||||
|
border-style: solid;
|
||||||
|
|
||||||
|
margin: 25px auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Part 2 */
|
||||||
|
|
||||||
|
a {
|
||||||
|
color:blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
color: cyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
a::selection {
|
||||||
|
background-color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: purple;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited:hover {
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="header">
|
||||||
|
<h1>Assignment 3: position</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="box">
|
||||||
|
<div class="one"></div>
|
||||||
|
<div class="two"></div>
|
||||||
|
<div class="three">
|
||||||
|
<div class="four"></div>
|
||||||
|
</div>
|
||||||
|
<div class="five">
|
||||||
|
<a href="https://developer.mozilla.org/en-US/docs/Web/CSS">CSS is awesome</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Before Width: | Height: | Size: 857 KiB After Width: | Height: | Size: 857 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,61 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>IT2805 assignment 5: JavaScript introduction</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.box {
|
||||||
|
/* Sets the size and position of each box */
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background-color: #185D8B;
|
||||||
|
margin: 10px;
|
||||||
|
|
||||||
|
/* Sets the font within each box*/
|
||||||
|
color: #fff;
|
||||||
|
font-family: Helvetica, Arial, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 200px;
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttons {
|
||||||
|
width: 200px;
|
||||||
|
margin: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="./script.js" defer></script>
|
||||||
|
<!--
|
||||||
|
I am including it here because it makes sense for
|
||||||
|
everything that's not content to be placed in the <head>.
|
||||||
|
I do know however that this usually causes problems with
|
||||||
|
accessing the DOM, because the script runs before the page
|
||||||
|
is loaded. The defer option will take care of this.
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1 id='title'></h1>
|
||||||
|
|
||||||
|
<h2>Part 5</h2>
|
||||||
|
<div class='buttons'>
|
||||||
|
<button id='displayButton'>Display: none </button>
|
||||||
|
<button id='visibilityButton'>Visibility: hidden</button>
|
||||||
|
<button id='resetButton'>Reset</button>
|
||||||
|
</div>
|
||||||
|
<div class='box' id='magic'> 1 </div>
|
||||||
|
<div class='box'> 2 </div>
|
||||||
|
|
||||||
|
<h2>Part 6</h2>
|
||||||
|
<ul id='tech'>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,91 @@
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Part 2 */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
console.log('PART 2')
|
||||||
|
|
||||||
|
/* Log i from 1 until i is no longer less than or equal to 20 */
|
||||||
|
for (i=1; i<=20; i++) {
|
||||||
|
console.log(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Part 3 */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
console.log('PART 3')
|
||||||
|
|
||||||
|
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
|
||||||
|
|
||||||
|
/* A function that returns eple and/or kake if it's divisible by 3 or 5, but defaults
|
||||||
|
* to n if it's not (an empty string combined with || will return the latter element)
|
||||||
|
*/
|
||||||
|
const eplekakeCheck = (n) => (n % 3 ? '' : 'eple') + (n % 5 ? '' : 'kake') || n;
|
||||||
|
|
||||||
|
/* Print the output of eplekakeCheck for each element in numbers */
|
||||||
|
for (i of numbers) {
|
||||||
|
console.log(eplekakeCheck(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Part 4 */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Store the DOM node as a variable and change its innerText */
|
||||||
|
const title = document.getElementById("title");
|
||||||
|
title.innerText = 'Hello JavaScript';
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Part 5 */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
const magicBox = document.getElementById('magic');
|
||||||
|
|
||||||
|
function changeDisplay () {
|
||||||
|
magicBox.style.display = 'none'
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeVisibility () {
|
||||||
|
magicBox.style.display = 'block'
|
||||||
|
magicBox.style.visibility = 'hidden'
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset () {
|
||||||
|
magicBox.style.display = 'block'
|
||||||
|
magicBox.style.visibility = 'visible'
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Connect each button to their respective function */
|
||||||
|
document.getElementById('displayButton').addEventListener('click', changeDisplay);
|
||||||
|
document.getElementById('visibilityButton').addEventListener('click', changeVisibility);
|
||||||
|
document.getElementById('resetButton').addEventListener('click', reset);
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Part 6 */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
const technologies = [
|
||||||
|
'HTML5',
|
||||||
|
'CSS3',
|
||||||
|
'JavaScript',
|
||||||
|
'Python',
|
||||||
|
'Java',
|
||||||
|
'AJAX',
|
||||||
|
'JSON',
|
||||||
|
'React',
|
||||||
|
'Angular',
|
||||||
|
'Bootstrap',
|
||||||
|
'Node.js'
|
||||||
|
];
|
||||||
|
|
||||||
|
const technologyList = document.getElementById("tech");
|
||||||
|
|
||||||
|
/*
|
||||||
|
for each technology, create an HTML element, add the technology as innertext and append
|
||||||
|
the element as a child of the list
|
||||||
|
*/
|
||||||
|
for (technology of technologies) {
|
||||||
|
const listElement = document.createElement('li');
|
||||||
|
listElement.innerText = technology;
|
||||||
|
technologyList.appendChild(listElement);
|
||||||
|
}
|
After Width: | Height: | Size: 46 KiB |
|
@ -0,0 +1,76 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Tax form</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="./style.css">
|
||||||
|
<script src="./script.js" defer></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<h1>Hero tax</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<form action="http://folk.ntnu.no/michaedm/norwegian-tax-administration/receive.php" method="post">
|
||||||
|
<label for="nameInput">Real name</label>
|
||||||
|
<input type="text" name="name" id="nameInput" pattern="[A-Za-z]+" title="Please use only alphanumeric characters" autofocus required>
|
||||||
|
|
||||||
|
<!-- Another option for genders would've been radio buttons -->
|
||||||
|
|
||||||
|
<label for="genderInput">Gender</label>
|
||||||
|
<select name="gender" id="genderInput" required>
|
||||||
|
<option value="">None</option>
|
||||||
|
<option value="male">Male</option>
|
||||||
|
<option value="female">Female</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label for="emailInput">E-mail</label>
|
||||||
|
<input type="email" name="email" id="emailInput" required>
|
||||||
|
|
||||||
|
<!-- This might not return the value in the DD.MM.YYYY format, but it's usually considered to be the safest and most correct method for date inputs. Also, even though the html validator doesn't like it, the regexp is only used as a fallback field if the browser has no native date picker (see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#Handling_browser_support). If you need conversion for something like a database, this would usually be done in javascript -->
|
||||||
|
|
||||||
|
<label for="birthdayInput">Birthdate</label>
|
||||||
|
<input type="date" name="birthday" id="birthdayInput" max="1987-12-31" pattern="\d{2}\.\d{2}\.\d{4}" required>
|
||||||
|
|
||||||
|
<label for="heroInput">Hero name</label>
|
||||||
|
<input type="text" name="hero" id="heroInput" required>
|
||||||
|
|
||||||
|
<div class="inline">
|
||||||
|
<label for="wearsSpandexInput">Do you wear spandex?</label>
|
||||||
|
<input type="checkbox" name="spandex" id="wearsSpandexInput" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="sliders">
|
||||||
|
|
||||||
|
<!-- I made these inputs as sliders because I felt it made more sense considering the "floatish" nature of these properties. If we had been allowed to use javascript for this task, I probably also would've added some kind of a number that would show the slider value. If it's really important that these values could be specified as an exact value, you would only need to change the type from "range" to "number" (and maybe add a required-attribute). Min, max and step will work in the same way. -->
|
||||||
|
|
||||||
|
<label for="strengthInput">Strength</label>
|
||||||
|
<input type="range" name="strength" id="strengthInput" min="1" max="10" step="1">
|
||||||
|
<label for="speedInput">Speed</label>
|
||||||
|
<input type="range" name="speed" id="speedInput" min="1" max="10" step="1">
|
||||||
|
|
||||||
|
<label for="intelligenceInput">Intelligence</label>
|
||||||
|
<input type="range" name="intelligence" id="intelligenceInput" min="1" max="10" step="1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="taxFields">
|
||||||
|
<label for="incomeInput">Income</label>
|
||||||
|
<input type="number" name="income" id="incomeInput" min="0" step="1" required>
|
||||||
|
|
||||||
|
<label for="wealthInput">Wealth</label>
|
||||||
|
<input type="number" name="wealth" id="wealthInput" min="0" step="1" required>
|
||||||
|
|
||||||
|
<label for="taxInput">Tax</label>
|
||||||
|
<input type="number" name="tax" id="taxInput" readonly>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="submit" value="Submit" id="submitButton">
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Questions
|
||||||
|
|
||||||
|
1. Why does the expression `0.1 + 0.2 === 0.3` evaluate to `false` in javascript?
|
||||||
|
|
||||||
|
Because of how most programming languages represent fractions, not all numbers can be represented correctly. Just like how we can't represent 1/3 in our base 10 number system, neither 0.1 nor 0.2 can't be represented without recurring digits, and therefore we end up with an approximation. `0.1 + 0.2` is a pretty common example of this, and it resolves to `0.30000000000000004`
|
||||||
|
|
||||||
|
2. What does the `method` attribute on a `form` element decide?
|
||||||
|
|
||||||
|
The `method` of on a `form` decides what kind of HTTP request to send on submission. `POST` and `ADD` are the most normal ones to use for this. You might use `GET` if the data isn't sensitive.
|
||||||
|
|
||||||
|
3. Explain why the form fields appear in the URL when the `method` on `form` element is changed to `GET`?
|
||||||
|
|
||||||
|
There are several types of HTTP requests. Some of them are quite similar but named differently for semantic purposes. `GET` and `POST` however, are quite different. `POST` is a generic request used for sending data to a server. Therefore, the packets contain data fields, and it can even be encrypted. `GET` however is only supposed to be used to fetch information from the server. `GET` requests have no data fields. If you want to include any modifiers or data in the request, it has to go in the URL of the request (with a few exceptions for metadata such as some kinds of system information, cookies, authentication certificates etc.)
|
||||||
|
|
||||||
|
4. Why is it considered bad practise to only validate form input with HTML5 and/or Javascript?
|
||||||
|
|
||||||
|
You can't run all kinds of validation in HTML. There are only basic, but often used options for HTML validation. Javascript however can do a lot more advanced validation, but using this to reimplement everything that the browser already does for you is bad practise. You would essentially be reinventing the wheel. It also means you'd have to take care of things like giving the user feedback on what's wrong. In the end, you would also want backend validation on a real project so no one can just bypass the html and javascript validation with sending an http request directly containing bad or even malicious data.
|
||||||
|
|
||||||
|
5. When is it appropriate to use `textarea` over `input`?
|
||||||
|
|
||||||
|
`textarea` is used whenever you have a long text, such as a tweet, a paragraph or really just anything longer than a few words. If the user is going to write more than one sentence, textarea is usually easier to work with than `input`. While it is still possible to force `input` to act as some kind of textfield, it's bad practise to do so. The text type `input` tag is really only meant for short entries such as names, usernames, food preferences etc.
|
||||||
|
|
||||||
|
[//]: # vim: set syntax=markdown:
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
const [incomeInput, wealthInput, taxInput] = ["incomeInput", 'wealthInput', 'taxInput']
|
||||||
|
.map(id => document.getElementById(id));
|
||||||
|
|
||||||
|
const tax = (income, wealth) => (0.35 * income) + (0.25 * wealth);
|
||||||
|
|
||||||
|
const updateTax = () => {
|
||||||
|
const [income, wealth] = [incomeInput.value, wealthInput.value]
|
||||||
|
.map(value => parseInt(value))
|
||||||
|
.map(value => isNaN(value) ? 0 : value);
|
||||||
|
taxInput.value = tax(income, wealth);
|
||||||
|
}
|
||||||
|
|
||||||
|
incomeInput.addEventListener('input', updateTax);
|
||||||
|
wealthInput.addEventListener('input', updateTax);
|
|
@ -0,0 +1,58 @@
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
background-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
color: #2b68d8;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background-color: #DFDFDF;
|
||||||
|
margin: 30px 10%;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin: 0 10%;
|
||||||
|
background-color: #DFDFDF;
|
||||||
|
padding: 50px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text], input[type=number], input[type=email], input[type=date], select {
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit] {
|
||||||
|
font-size: large;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #2b68d8;
|
||||||
|
background-color: #DDDDDD;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit]:hover {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#sliders input, #taxFields input {
|
||||||
|
display: inline;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sliders {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#taxFields {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inline * {
|
||||||
|
display: inline;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
The PDF didn't want to cooperate so here you have the table for part 6.
|
||||||
|
|
||||||
|
| Real name | Gender | E-Mail | Birthyear | Hero name | Spandex | Strength | Speed | Intelligence | Wealth | Income | Tax
|
||||||
|
|-------------|--------|----------------------------|-----------|-----------|---------|----------|-------|--------------|----------- |-----------|-----
|
||||||
|
| Nick Nedd | Male | nick@tick.com | 1976 | The Tick | Yes | 9 | 7 | 5 | 0 | 90 287 | 29 794
|
||||||
|
| Bruce Wayne | Male | bruce@wayneenterprises.com | 1974 | Batman | No | 7 | 4 | 9 | 50 144 501 | 3 343 891 | 11 132 384
|
||||||
|
| Selina Kyle | Female | selina@whiskas.com | 1977 | Catwoman | Yes | 6 | 6 | 9 | 2 987 323 | 0 | 597 464
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<people>
|
||||||
|
<person>
|
||||||
|
<name>Nick Nedd</name>
|
||||||
|
<gender>Male</gender>
|
||||||
|
<email>nick@tick.com</email>
|
||||||
|
<birthyear>1976</birthyear>
|
||||||
|
<hero>The Tick</hero>
|
||||||
|
<spandex>True</spandex>
|
||||||
|
<strength>9</strength>
|
||||||
|
<speed>7</speed>
|
||||||
|
<intelligence>5</intelligence>
|
||||||
|
<wealth>0</wealth>
|
||||||
|
<income>90287</income>
|
||||||
|
<tax>29794</tax>
|
||||||
|
</person>
|
||||||
|
<person>
|
||||||
|
<name>Bruce Wayne</name>
|
||||||
|
<gender>Male</gender>
|
||||||
|
<email>bruce@wayneenterprises.com</email>
|
||||||
|
<birthyear>1974</birthyear>
|
||||||
|
<hero>Batman</hero>
|
||||||
|
<spandex>False</spandex>
|
||||||
|
<strength>7</strength>
|
||||||
|
<speed>4</speed>
|
||||||
|
<intelligence>9</intelligence>
|
||||||
|
<wealth>50144501</wealth>
|
||||||
|
<income>3343891</income>
|
||||||
|
<tax>11132384</tax>
|
||||||
|
</person>
|
||||||
|
<person>
|
||||||
|
<name>Selina Kyle</name>
|
||||||
|
<gender>Female</gender>
|
||||||
|
<email>selina@whiskas.com</email>
|
||||||
|
<birthdate>1977</birthdate>
|
||||||
|
<hero>Catwoman</hero>
|
||||||
|
<spandex>True</spandex>
|
||||||
|
<strength>6</strength>
|
||||||
|
<speed>6</speed>
|
||||||
|
<intelligence>9</intelligence>
|
||||||
|
<wealth>2987323</wealth>
|
||||||
|
<income>0</income>
|
||||||
|
<tax>597464</tax>
|
||||||
|
</person>
|
||||||
|
<people>
|
|
@ -0,0 +1,71 @@
|
||||||
|
body {
|
||||||
|
background-color: #272822;
|
||||||
|
color: #F8F8F8;
|
||||||
|
margin: 5% 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
text-align: center;
|
||||||
|
color: #A6E22E;
|
||||||
|
font-size: 4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoField {
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0 auto;
|
||||||
|
color: #F8F8F8;
|
||||||
|
background-color: #494b41;
|
||||||
|
font-size: 2em;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoButton {
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
margin: 1em auto;
|
||||||
|
color: black;
|
||||||
|
background-color: #FD971F;
|
||||||
|
font-size: 1.5em;
|
||||||
|
filter: drop-shadow(0.5em 0.5em 2px #191a16);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoSummary {
|
||||||
|
font-size: 3em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoList {
|
||||||
|
list-style-type: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=checkbox] {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
margin-right: 2em;
|
||||||
|
vertical-align: middle;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoList>li>span {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#todoList>li {
|
||||||
|
margin-bottom: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Monokai rainbow list :DDD */
|
||||||
|
#todoList>li:nth-child(7n+1) {color: #F92672;}
|
||||||
|
#todoList>li:nth-child(7n+2) {color: #FD971F;}
|
||||||
|
#todoList>li:nth-child(7n+3) {color: #E69F66;}
|
||||||
|
#todoList>li:nth-child(7n+4) {color: #E6DB74;}
|
||||||
|
#todoList>li:nth-child(7n+5) {color: #A6E22E;}
|
||||||
|
#todoList>li:nth-child(7n+6) {color: #66D9EF;}
|
||||||
|
#todoList>li:nth-child(7n) {color: #AE81FF;}
|
||||||
|
|
||||||
|
.strikethrough {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Todo</title>
|
||||||
|
<link rel="stylesheet" href="./todo.css">
|
||||||
|
<script src="./todo.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1 id="title">Todo-list</h1>
|
||||||
|
<textarea id="todoField" cols="60" rows="2" autofocus ></textarea>
|
||||||
|
<button id="todoButton">Add task (Enter)</button>
|
||||||
|
<div id="todoSummary"></div>
|
||||||
|
<ul id="todoList"></ul>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,91 @@
|
||||||
|
const todoField = document.getElementById("todoField");
|
||||||
|
const todoButton = document.getElementById("todoButton");
|
||||||
|
const todoSummary = document.getElementById("todoSummary");
|
||||||
|
const todoList = document.getElementById("todoList");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task for the todolist
|
||||||
|
* @typedef {Object} Task
|
||||||
|
* @property {number} createdAt - Timestamp of the time that the task was created.
|
||||||
|
* @property {string} description - Description of the task.
|
||||||
|
* @property {boolean} isCompleted - Whether or not the task is completed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const tasks = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add task to both tasks and DOM
|
||||||
|
*/
|
||||||
|
addTask = () => {
|
||||||
|
tasks.push({
|
||||||
|
createdAt: Date.now(),
|
||||||
|
description: todoField.value,
|
||||||
|
isCompleted: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const taskElement = createTaskElement(tasks[tasks.length - 1]);
|
||||||
|
todoList.prepend(taskElement);
|
||||||
|
|
||||||
|
todoField.value = '';
|
||||||
|
todoField.focus();
|
||||||
|
|
||||||
|
updateSummary();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate HTML element for a task
|
||||||
|
* @param {Task} task - The task to be converted into an html element
|
||||||
|
* @return {HTMLLIElement} The <li> element
|
||||||
|
*/
|
||||||
|
createTaskElement = (task) => {
|
||||||
|
const listItem = document.createElement('li');
|
||||||
|
|
||||||
|
const checkbox = document.createElement('input');
|
||||||
|
checkbox.type = 'checkbox';
|
||||||
|
checkbox.name = tasks.length - 1
|
||||||
|
checkbox.addEventListener('change', updateCheckbox);
|
||||||
|
listItem.appendChild(checkbox);
|
||||||
|
|
||||||
|
const description = document.createElement('span');
|
||||||
|
description.innerText = task.description;
|
||||||
|
listItem.appendChild(description);
|
||||||
|
|
||||||
|
return listItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to react to change on a checkbox
|
||||||
|
* @param {Event} event - the event raised by the eventlistener
|
||||||
|
*/
|
||||||
|
updateCheckbox = (event) => {
|
||||||
|
const index = tasks.length - event.target.name - 1;
|
||||||
|
tasks[index].isCompleted = event.target.checked;
|
||||||
|
|
||||||
|
const descriptionSpanClasses = todoList
|
||||||
|
.children[index]
|
||||||
|
.getElementsByTagName('span')[0]
|
||||||
|
.classList
|
||||||
|
|
||||||
|
if (event.target.checked) descriptionSpanClasses.add('strikethrough');
|
||||||
|
else descriptionSpanClasses.remove('strikethrough');
|
||||||
|
|
||||||
|
updateSummary();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the summary span with new task values
|
||||||
|
*/
|
||||||
|
updateSummary = () => {
|
||||||
|
const tasksCompleted = tasks.filter(task => task.isCompleted).length;
|
||||||
|
todoSummary.innerText = `${tasksCompleted}/${tasks.length} completed.`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the global keypresses and react on certain ones.
|
||||||
|
*/
|
||||||
|
handleKeys = (event) => {
|
||||||
|
if (event.which === 13 && document.activeElement === todoField) addTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
todoButton.addEventListener('click', addTask);
|
||||||
|
document.addEventListener('keyup', handleKeys);
|
|
@ -0,0 +1,184 @@
|
||||||
|
<!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) => {
|
||||||
|
const yOffset = i => canvas.height * (n - i + 1 ) / (n+1);
|
||||||
|
for (let i = 1; i <= n; i++)
|
||||||
|
drawLineWithText(step * i, 50, yOffset(i), canvas.width - 100, yOffset(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
while (true)
|
||||||
|
for (color of colors)
|
||||||
|
yield color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw a legend 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 = i => canvas.height / 12 + 30 * i;
|
||||||
|
for (i in properties)
|
||||||
|
drawLabel(properties[i], colors.next().value, yOffset(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) =>
|
||||||
|
drawRectangle(
|
||||||
|
x,
|
||||||
|
adjustY(value),
|
||||||
|
width / (values.length) - sep,
|
||||||
|
canvas.height - adjustY(value),
|
||||||
|
colors.next().value
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
const xOffset = i => x + i * (sep + width / (values.length));
|
||||||
|
for (let i=0; i<values.length; i++)
|
||||||
|
drawBar(values[i], xOffset(i));
|
||||||
|
|
||||||
|
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 / (range + step));
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
];
|