- let rc = 1000;
- let cc = 1, ic = 0;
- let s = 2.25*rc, o = -.5*s;
- let min = 3, max = 9, p = min;
- let ba = 2*Math.PI/p;
- let cos = +(Math.cos(.5*ba)).toFixed(2);
- let rp = .003*rc, ms = 4*rp, mo = -.5*ms;
- let vx = [];
- for(let i = 0; i < p; i++)
- let ca = i*ba;
- vx.push([rc*Math.cos(ca), rc*Math.sin(ca)])
- vx = vx.map(c => c.map(k => +k.toFixed(1)).join(' ')).join(', ')
body(style=`--p: ${p}; --cc: ${cc}; --ic: ${ic}; --cos: ${cos}`)
form
.wrap.wrap--opt(role='group' aria-label='Group of checkboxes that control whether the polygon-related circles are shown or not.')
input#cc(type='checkbox' checked=cc === 1)
label.cc(for='cc') circumcircle
input#ic(type='checkbox' checked=ic === 1)
label.ic(for='ic') incircle
.wrap.wrap--num(role='group' aria-label='Slider controlling the number of polygon vertices. In the no JS case, dragging its thumb cannot change anything, so the actual range input does not get diplayed, only the label and the initial output.' style=`--min: ${min}; --max: ${max}`)
label(for='p') Number of polygon vertices
input#p(type='range' min=min max=max value=p)
output(for='p')
svg(viewBox=[o, o, s, s].join(' ') style=`--sw: ${.01*rc}px`)
marker#cm(viewBox=[mo, mo, ms, ms].join(' ') markerWidth=ms markerHeight=ms)
circle.point.cc(r=rp)
marker#im(viewBox=[mo, mo, ms, ms].join(' ') markerWidth=ms markerHeight=ms)
circle.point.ic(r=rp)
polygon(points=vx)
circle.circ.cc(r=rc)
circle.circ.ic(r=rc)
- for(let i = 0; i < max; i++)
line.rad.ic(x2=rc style=`--i: ${i}`)
line.rad.cc(x2=rc style=`--i: ${i}`)
circle.point.o(r=.015*rc)
View Compiled
$c0: #ff7a18, #af002d, #319197;
$c1: #00908a, #41024f, #f60c61, #ff6a00, #ffb231;
$cd: #170e27;
$cm: #434343;
$cl: #d4d4d4;
$track-p: Min(.5em, 2vw);
$track-u: 2.125em;
$track-h: .25em;
$track-r: .5*$track-h;
$thumb-d: 1em;
$thumb-r: .5*$thumb-d;
$arrow-a: 70deg;
$arrow-b: .25em;
$arrow-r: .25em;
$label-d: 3ch;
$label-o: -.5*$label-d;
$t: .3s;
@mixin track() {
border: none;
width: 100%; height: $track-h;
border-radius: $track-r;
background:
radial-gradient(circle at var(--pos),
transparent calc(var(--js)*(#{$thumb-r} - 2px)),
#ccc calc(var(--js)*(#{$thumb-r} - 1px)))
}
@mixin thumb($f: 0) {
margin-top: $f*($track-r - $thumb-r);
border: none;
width: $thumb-d; height: $thumb-d;
border-radius: 50%;
background: currentcolor;
filter: Invert(var(--not-focus)) brightness(calc(1 + .9*var(--not-focus)));
transition: $t;
transition-property: transform, filter;
.js & { transform: scale(calc(.5*(1 + var(--focus)))) }
}
*, ::after {
box-sizing: inherit;
margin: 0;
border: none;
padding: 0;
background: transparent;
color: inherit;
font: inherit;
}
html {
--k: var(--js, 0);
--not-k: calc(1 - var(--k));
&.js { --js: 1 }
}
body {
--i: var(--narr, 1);
--not-i: calc(1 - var(--i));
--j: var(--wide, 1);
--not-j: calc(1 - var(--j));
--c: #{nth($c0, 1)};
display: grid;
overflow-x: hidden;
grid-template-rows: max-content 1fr;
height: 100vh;
font: 400 clamp(.875em, 6.25vw, 1.5em)/ 1.375 raleway, sans-serif;
@media (max-width: 745px) { --wide: 0 }
@media (min-width: 400px) { --narr: 0 }
}
form {
display: grid;
grid-gap: $track-p;
padding: $track-p;
background: $cd;
color: $cl
}
.wrap {
padding: .25em $track-p;
border-radius: 5px;
box-shadow: 2px 2px #000;
background: $cm;
filter: grayScale(var(--not-focus));
counter-reset: n var(--n);
transition: filter $t;
&--opt {
display: flex;
flex-wrap: wrap;
justify-content: center
}
&--num {
--focus: 0;
--not-focus: calc(1 - var(--focus));
--range: calc(var(--max) - var(--min));
--track-w: clamp(4.5em, calc(100vw - 4*#{$track-p}), calc(var(--range)*#{$track-u}));
--pos: calc(#{$thumb-r} + (var(--p) - var(--min))/var(--range)*(var(--track-w) - #{$thumb-d}));
display: grid;
place-content: center;
counter-reset: p var(--p);
label { margin: 0 calc(var(--js)*var(--j)*#{$track-p}) }
&:focus-within { --focus: 1 }
}
> * { align-self: center }
}
input[type='checkbox'] {
z-index: 2;
width: $thumb-d; height: $thumb-d;
opacity: 0;
cursor: pointer;
+ label {
--focus: 0;
--not-focus: calc(1 - var(--focus));
display: flex;
z-index: 1;
align-items: center;
margin: 0 $track-p 0 calc(-1*(#{$thumb-d} + #{$track-p}));
padding: 0 $track-p;
color: var(--c);
filter: grayScale(var(--not-focus)) brightness(calc(1 + .5*var(--not-focus)));
transition: filter $t;
cursor: pointer;
&::before {
display: grid;
place-content: center;
margin: 0 $track-p 0 0;
width: $thumb-d; height: $thumb-d;
box-shadow: inset 0 0 0 2px var(--c);
color: rgba(nth($c0, 1), var(--mc));
content: '✔'
}
}
&:focus + label { --focus: 1 }
}
input[type='range'] {
&, &::-webkit-slider-thumb,
&::-webkit-slider-runnable-track {
-webkit-appearance: none
}
display: var(--js, none);
grid-area:
calc(1 + var(--not-j))/
calc(1 + var(--j));
width: var(--track-w); height: $thumb-d;
color: var(--c);
cursor: pointer;
&::-webkit-slider-runnable-track { @include track() }
&::-moz-range-track { @include track() }
&::-webkit-slider-thumb { @include thumb(1) }
&::-moz-range-thumb { @include thumb() }
&:focus { outline: solid 0 transparent }
}
output {
grid-area:
calc(1 + var(--i) + var(--not-j))/
calc(1 + 2*var(--k)*var(--not-i) + var(--not-k));
justify-self: start;
margin:
calc(var(--js)*(var(--i)*#{$track-p} + var(--not-i)*#{-$arrow-b}))
0
calc(var(--js)*var(--not-i)*#{-$arrow-b})
calc(var(--js)*var(--not-i)*#{$track-p});
min-width: 2em;
border-radius: $arrow-r;
transform: translate(calc(var(--i)*(var(--pos) - 50%)));
background: rgba(nth($c0, 1), var(--k));
text-align: center;
&::after { content: counter(p) }
@supports (background: conic-gradient(red, tan)) {
.js & {
--xy: calc(var(--i)*50%) calc(var(--not-i)*50%);
margin-top: calc(var(--not-i)*#{-$arrow-b} + var(--i)*#{$track-p});
border: solid $arrow-b transparent;
border-radius: $arrow-b + $arrow-r;
--mask:
linear-gradient(red, red) padding-box,
conic-gradient(from calc(90deg - .5*#{$arrow-a} + var(--i)*90deg) at var(--xy),
red #{$arrow-a}, transparent 0%)
var(--xy)/ 50% 50% no-repeat border-box;
-webkit-mask: var(--mask);
mask: var(--mask);
}
}
}
svg {
place-self: stretch;
fill: none;
stroke-width: var(--sw)
}
marker { overflow: visible }
.point {
fill: var(--gc);
stroke: $cd;
stroke-width: calc(.625*var(--sw));
marker & { stroke-width: calc(.1*var(--sw)) }
}
polygon {
stroke: nth($c0, 1);
stroke-linejoin: round
}
.ic {
--mc: var(--ic);
--mf: var(--cos);
--gc: #{nth($c0, 3)}
}
.cc {
--mc: var(--cc);
--mf: 1;
--gc: #{nth($c0, 2)}
}
.circ, .rad { stroke: var(--gc) }
.circ {
opacity: var(--mc);
&.ic {
transform: scale(var(--cos));
stroke-width: calc(var(--sw)/var(--cos));
}
}
[id='im'] circle { transform: scalex(calc(1/var(--cos))) }
line {
transform:
rotate(calc((var(--i) + var(--o, 0))/var(--p)*1turn))
scalex(var(--mf));
stroke-width: calc(.5*var(--sw));
stroke-dasharray: calc(2*var(--sw));
opacity: calc(var(--mc)*(var(--p) - var(--i)));
marker-end: url(#cm);
&.ic {
--o: .5;
marker-end: url(#im)
}
}
.o {
--gc: #{nth($c1, 5)};
opacity: calc(var(--cc) + var(--ic))
}
View Compiled
document.documentElement.classList.add('js');
const _BODY = document.body,
_POLY = document.querySelector('polygon'),
RC = +document.querySelector('.circ.cc').getAttribute('r');
addEventListener('input', e => {
let _t = e.target, typ = _t.type, val;
switch(_t.type) {
case 'checkbox':
val = 1*_t.checked;
break;
case 'range':
if(typ === 'range') {
val = +_t.value;
let ba = 2*Math.PI/val, vx = [];
for(let i = 0; i < val; i++) {
let ca = i*ba;
vx.push([RC*Math.cos(ca), RC*Math.sin(ca)])
}
vx = vx.map(c => c.map(k => +k.toFixed(1)).join(' ')).join(', ');
_POLY.setAttribute('points', vx);
_BODY.style.setProperty('--cos', Math.cos(.5*ba))
}
}
document.body.style.setProperty(`--${_t.id}`, val);
}, false);
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.