Skip to content

Instantly share code, notes, and snippets.

@peacefullatom
Created January 8, 2020 12:57
Show Gist options
  • Save peacefullatom/5e5d64f1aa4fdc2090dfeb39d7ef6463 to your computer and use it in GitHub Desktop.
Save peacefullatom/5e5d64f1aa4fdc2090dfeb39d7ef6463 to your computer and use it in GitHub Desktop.
Gear playground
:root {
--smokey: #f5f5f5;
--darky: #262625;
--thickness: 0.1vmin;
--half: 50%;
--border: var(--thickness) solid var(--smokey);
--border-radius: var(--half);
}
body,
html {
display: flex;
width: 100%;
height: 100%;
margin: 0;
background: var(--darky);
color: var(--smokey);
justify-content: center;
align-items: center;
flex-direction: column;
}
.controls {
display: flex;
width: 90vmin;
flex-wrap: wrap;
}
.controls .item {
line-height: 2rem;
margin-right: 1rem;
}
#container {
position: relative;
display: flex;
border: var(--border);
margin: 10vmin;
justify-content: center;
align-items: center;
border-radius: var(--border-radius);
}
#container .cover {
position: relative;
width: 100%;
height: 100%;
background: var(--darky);
border-radius: var(--border-radius);
z-index: 1;
}
#container .cover::before {
position: absolute;
width: var(--half);
height: var(--half);
left: var(--half);
top: var(--half);
transform: translateX(-50%) translateY(-50%);
background: var(--darky);
border-radius: var(--border-radius);
content: "";
border: var(--border);
}
#container .tooth {
position: absolute;
box-sizing: border-box;
}
#container .tooth::before {
position: absolute;
width: 100%;
height: 100%;
border: var(--border);
content: "";
background: var(--darky);
}
#container .tooth.circle::before {
border-radius: var(--border-radius);
}
#container .tooth.triangle::before {
transform: rotateZ(45deg);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Gear</title>
<link rel="stylesheet" type="text/css" href="gear.css" />
</head>
<body>
<div id="container"></div>
<div class="controls">
<div class="item">
<label for="teeth">teeth:</label>
<input
id="teeth"
max="72"
min="3"
oninput="setTeeth(value)"
type="number"
value="3"
/>
</div>
<div class="item">
<label for="height">height:</label>
<input
id="height"
max="30"
min="10"
oninput="setHeight(value)"
step="1"
type="number"
value="10"
/>
</div>
<div class="item">
<label for="shape">shape:</label>
<select id="shape" oninput="setShape(value)">
<option selected>square</option>
<option value="circle">circle</option>
<option value="triangle">triangle</option>
</select>
</div>
<div class="item">
<label for="thickness">thickness:</label>
<input
id="thickness"
max="10"
min="1"
oninput="setThickness(value)"
step="1"
type="number"
value="1"
/>
</div>
<div class="item">
<label for="angle">angle:</label>
<input
id="angle"
max="360"
min="0"
oninput="setAngle(value)"
step="5"
type="number"
value="0"
/>
</div>
</div>
<script src="gear.js"></script>
</body>
</html>
/**
* the gear container
* @type {HTMLDivElement}
*/
let container = null;
/**
* the gear radius
* @type {number}
*/
const radius = 10;
/**
* number of teeth
* @type {number}
*/
let teeth = 3;
/**
* tooth height modifier
* @type {number}
*/
let height = 10;
/**
* tooth shape name
* @type {string}
*/
let shape = "";
/**
* line thickness
* @type {number}
*/
let thickness = 1;
/**
* gear angle
* @type {number}
*/
let angle = 45;
/**
* set number of teeth
* @param {number} value number of teeth
*/
function setTeeth(value) {
teeth = value;
update();
}
/**
* set modifier for tooth height
* @param {number} value tooth height modifier
*/
function setHeight(value) {
height = value;
update();
}
/**
* set name of shape
* @param {string} value shape name
*/
function setShape(value) {
shape = value;
update();
}
/**
* set thickness
* @param {number} value thickness value
*/
function setThickness(value) {
document.documentElement.style.setProperty(
"--thickness",
`${value / 10}vmin`
);
}
/**
* set angle value
* @param {number} value angle value
*/
function setAngle(value) {
angle = value;
update();
}
/**
* set a value to an input
* @param {string} id input id
* @param {number} value input value
*/
function setupInput(id, value) {
const input = document.getElementById(id);
if (input) {
input.value = value;
}
}
/**
* update the gear
*/
function update() {
if (container) {
// calculate the container dimensions
const size = `${radius * 3}vmin`;
// calculate the angle between teeth
const step = 360 / teeth;
// calculate the base dimension of the tooth
const side = (2 * Math.PI * radius) / (teeth * (Math.PI / 2));
// calculate the tooth displacement
const displacement = radius * 1.5;
// setup container
container.style.width = size;
container.style.height = size;
container.style.transform = `rotate(${angle}deg)`;
container.innerHTML = null;
// draw teeth
for (var i = 0; i < teeth; i++) {
// create tooth
const tooth = document.createElement("div");
tooth.className = `tooth ${shape}`;
// set size for the triangle-shaped tooth
if (shape === "triangle") {
const length = `${(side / 2) * ((height - 1) / 10)}vmin`;
tooth.style.height = length;
tooth.style.width = length;
} else {
// set size for the square and circle-shaped teeth
tooth.style.height = `${side}vmin`;
tooth.style.width = `${side * ((height - 1) / 10)}vmin`;
}
// place the tooth
tooth.style.transform = `rotateZ(${i *
step}deg) translateX(${displacement}vmin)`;
// append tooth to the container
container.appendChild(tooth);
}
// restore cover
const cover = document.createElement("div");
cover.className = "cover";
container.appendChild(cover);
}
}
/**
* perform initial values setup
*/
function init() {
setupInput("teeth", teeth);
setupInput("height", height);
setupInput("thickness", thickness);
setupInput("angle", angle);
container = document.getElementById("container");
update();
}
init();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment