<!DOCTYPE html>
<html>
<head>
<style>
form {
font: 400 16px/1.25 Consolas
}
input,
output,
button {
display: inline-block;
font: inherit
}
input {
text-align: center;
}
img {
display: block;
margin: 0 auto;
height: 250px;
width: auto;
}
</style>
</head>
<body>
<form id='poly' onsubmit='return false'>
<fieldset>
<legend>Regular Polygons</legend>
<label> Sides: </label>
<input id='qty' type='number' min='3' max='20'>
<button id='btn'>GO</button>
</fieldset>
<fieldset id='view'></fieldset>
</form>
<script>
/* Composite Objects */
/*
getType has the name() method which will convert props.sides into the
proper index of the types array to get the correct value for prop.type
*/
const getType = (props, types) => ({
name: () => {
props.type = types[props.sides - 3];
}
});
/*
getLinx has the link() and image() methods props.type is used by the former
and props.sides and the dir array are used by the later to interpolate
strings into template literals that become urls for props.url and props.img.
*/
const getLinx = (props, dir) => ({
link: () => {
props.url = `https://en.wikipedia.org/wiki/${props.type}`;
},
image: () => {
switch (props.sides) {
case 4:
props.img = `https://upload.wikimedia.org/wikipedia/commons/3/3d/Six_Quadrilaterals.svg`;
break;
default:
props.img = `https://upload.wikimedia.org/wikipedia/commons/${dir[props.sides - 3]}/Regular_polygon_${props.sides}_annotated.svg`;
break;
}
}
});
/*
polygon() function factory passes 2 parameters sides (Number) and tag
(String) props is the object that will have the three methods name(), link(),
and image() by concatenative inheritance using Object.assign().
*/
const polygon = (sides, tag) => {
const types = ["Triangle", "Quadrilateral", "Pentagon", "Hexagon", "Septagon", "Octogon", "Nonagon", "Decagon", "Undecagon", "Dodecagon", "Tridecagon", "Tetradecagon", "Pentadecagon", "Hexadecagon", "Heptadecagon", "Octadecagon", "Enneadecagon", "Icosagon"];
const dir = ["e/eb", "3/3d", "0/01", "3/38", "7/75", "e/e5", "b/ba", "b/b9", "f/f8", "0/06", "a/a6", "e/e1", "d/d0", "e/e4", "c/c6", "d/d8", "1/18", "2/23"];
let props = {
tag: tag,
sides: sides,
type: '',
url: '',
img: '',
desc: ''
};
return Object.assign(props, getType(props, types), getLinx(props, dir));
};
/* DOM Interface */
/*
HTMLFormControlsCollection is a terse API that references tags by id or name
*/
const poly = document.forms.poly;
const qty = poly.qty;
const view = poly.view;
/*
#btn is regustered to the click event. When triggered, the value of #qty
(.valueAsNumber) and the number of #view's chid elements (.childElementCount)
become arguments for the function displayPoly().
*/
poly.btn.addEventListener('click', (e) => {
const vert = qty.valueAsNumber;
const count = view.childElementCount;
displayPoly(vert, count);
});
/*
displayPoly() passes the number from #qty and interpolates the number #view
with a generic word to create a unique string to pass it to polygon() as the
2nd argument. Next, the object creayed by polygon is returned and referenced
as shape. shape's methods are invoked and then the new values are generated.
The values of type, url, and img are interpolated into a string which is then
rendered as HTML and prepended to #view.
*/
const displayPoly = (number, index) => {
let name = `shape${index}`;
let shape = polygon(number, name);
shape.name();
shape.link();
shape.image();
let Type = shape.type;
let Url = shape.url;
let Img = shape.img;
let item = `
<figure id='${name}'>
<figcaption title='${shape.sides} Sides'>${Type}</figcaption>
<a href='${Url}'>
<img src='${Img}'>
</a>
</figure>
`;
view.insertAdjacentHTML('afterbegin', item);
return false;
};
</script>
</body>
</html>