- let r_max = 500, r_min = 200;
- let r = .8*r_max;
- let a_max = 180, a_min = -a_max;
- let a = Math.round(a_max/3);
- let rad = a*Math.PI/180;
- let cos = +(Math.cos(rad)).toFixed(3);
- let sin = +(Math.sin(rad)).toFixed(3);
- let p = .2*r_max, ax = r_max + 2*p;
- let d = 2*ax, o = -.5*d;
- let as = .2*p, ah = .5*as, av = .3*as;
- let rp = .05*p, fs = .4*p
mixin fo(idx, cls)
foreignObject(class=cls style=idx.split(' ').length < 2 ? `--val: var(--${idx})` : null)
output(xmlns='http://www.w3.org/1999/xhtml' for=idx)
body(style=`--r: ${r}; --r-min: ${r_min}; --r-max: ${r_max}; --a: ${a}; --cos: ${cos}; --sin: ${sin}`)
form
.wrap.wrap--r(style=`--min: var(--r-min); --max: var(--r-max); --val: var(--r)` role='group' aria-label='control the radius of the circle our point is on')
label(for='r') radius
input#r(type='range' min=r_min max=r_max value=r)
output(for='r')
.wrap.wrap--a(style=`--min: ${a_min}; --max: ${a_max}; --val: var(--a)` role='group' aria-label='control the angle of the radius to our point with respect to the horizontal axis')
label(for='a') angle
input#a(type='range' min=a_min max=a_max value=a)
output(for='a')
svg(viewBox=[o, o, d, d].join(' ') style=`font-size: ${fs}px`)
defs: path#arr(d=`M0 0l${ah}${-as}${-ah} ${av}${-ah}${-av}z`)
path.axes(d=`M${ax} 0H${-ax}M0${-ax}V${ax}`)
use.axes(xlink:href='#arr' transform=`rotate(-90) translate(0 ${-o})`)
use.axes(xlink:href='#arr' y=-o)
text.axes(x=-(.5*fs + o) y=-as) x
text.axes(y=-(.5*fs + o) x=-as text-anchor='end') y
line.guide(x2=r_max)
line.guide(y2=r_max)
line.proj(x2=r_max)
line.proj(y2=r_max)
g.meas
circle.arc(r=.1*r_max pathLength=360)
use.arr(xlink:href='#arr')
line.rad(x2=r_max)
circle.main
circle.point.proj.point--x(r=rp)
circle.point.proj.point--y(r=rp)
circle.point.rad.point--x.point--y(r=1.5*rp)
+fo('a', 'meas')
+fo('r', 'rad')
+fo('r a', 'cart')
pre
div.token--form
var.token--var x
span.token--oper =
var.token--var r
span.token--oper ·
span.token--func cos
span.token--punc (
span.token--arg: var.token--var θ
span.token--punc )
span.token--oper =
output.token--len(for='r' style=`--val: var(--r)`)
span.token--oper ·
span.token--func cos
span.token--punc (
span.token--arg: output.token--ang(for='a' style=`--val: var(--a)`)
span.token--punc )
span.token--oper =
output.token--coord(for='r a' style=`--val: var(--x)`)
div.token--form
var.token--var y
span.token--oper =
var.token--var r
span.token--oper ·
span.token--func sin
span.token--punc (
span.token--arg: var.token--var θ
span.token--punc )
span.token--oper =
output.token--len(for='r' style=`--val: var(--r)`)
span.token--oper ·
span.token--func sin
span.token--punc (
span.token--arg: output.token--ang(for='a' style=`--val: var(--a)`)
span.token--punc )
span.token--oper =
output.token--coord(for='r a' style=`--val: var(--y)`)
View Compiled
$c: #00908a, #41024f, #f60c61, #ff6a00, #ffb231;
$track-p: Min(4vw, .5em);
$track-u: 1px;
$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 + .25*var(--not-focus)));
transition: $t;
transition-property: transform, filter;
.js & { transform: scale(calc(.5*(1 + var(--focus)))) }
}
@property --houdini {
syntax: '<integer>';
initial-value: 1;
inherits: true
}
@property --x {
syntax: '<integer>';
initial-value: 0;
inherits: true
}
@property --y {
syntax: '<integer>';
initial-value: 0;
inherits: true
}
/* --------------- GENERAL --------------- */
* {
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 {
--s: var(--houdini, 0);
--i: var(--narr, 1);
--not-i: calc(1 - var(--i));
--j: var(--wide, 1);
--not-j: calc(1 - var(--j));
--x: calc(var(--r)*var(--cos));
--y: calc(var(--r)*var(--sin));
--u: '';
display: grid;
grid-gap: 1vmin;
grid-template-rows: max-content 1fr max-content;
overflow-x: hidden;
margin: 0;
height: 100vh;
font: 400 clamp(.875em, 6.25vw, 1.5em)/ 1.375 raleway, sans-serif;
@media (max-width: 575px) { --wide: 0 }
@media (min-width: 470px) { --narr: 0 }
}
form, pre { background: #100e17 }
[for], pre { color: #fafafa }
pre, output { font-family: ubuntu mono, consolas, monaco, monospace }
text, var { font-style: italic; font-family: serif }
/* --------------- FORM --------------- */
.wrap {
--focus: 0;
--not-focus: calc(1 - var(--focus));
--range: calc(var(--max) - var(--min));
--track-w: clamp(4.5em, calc(100vw - 2*#{$track-p}), calc(var(--range)*#{$track-u} + #{$thumb-d}));
--pos: calc(#{$thumb-r} + (var(--val) - var(--min))/var(--range)*(var(--track-w) - #{$thumb-d}));
display: grid;
justify-self: stretch;
place-content: center;
padding: .25em $track-p;
filter: grayScale(var(--not-focus));
counter-reset: n var(--n);
transition: filter $t;
&--r { --c: #{nth($c, 3)} }
&--a { --c: #{nth($c, 4)} }
> * { align-self: center }
label { margin: 0 calc(var(--js)*var(--j)*1vw) }
&:focus-within { --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 {
border-radius: 5px;
text-align: center;
counter-reset: val var(--val);
form & {
grid-area:
calc(1 + var(--i) + var(--not-j))/
calc(1 + var(--k)*(var(--not-i) + var(--j)) + var(--not-k));
justify-self: start;
min-width: 2.5em;
margin:
calc(var(--js)*(var(--i)*1vw + var(--not-i)*#{-$arrow-b}))
0
calc(var(--js)*var(--not-i)*#{-$arrow-b})
calc(var(--js)*var(--not-i)*1vw);
transform: translate(calc(var(--i)*(var(--pos) - 50%)));
@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)*1vw);
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);
}
}
}
:not(pre) & { background: var(--c) }
&::before { content: counter(val) var(--u) }
}
[for='a'] { --u: '°' }
/* --------------- VISUAL --------------- */
svg {
--c: #000;
--rf: calc(var(--r)/var(--r-max));
--mov: #{unquote(' ')};
--ang-a: calc(var(--a)*1deg);
--sgn-a: clamp(-1, var(--a), 1);
--abs-a: calc(var(--sgn-a)*var(--a));
--r-arc: calc(.5px*var(--r-min));
place-self: stretch;
fill: none;
* {
stroke: var(--c);
stroke-width: calc(var(--r-max)*var(--sm, .004px))
}
}
.axes { --c: #c0c0c0 }
text { stroke: none }
text, use, .point { fill: var(--c); }
.meas, .rad { --sm: .01px }
.meas {
--a-cut: clamp(0, calc(var(--abs-a) - 15), 1);
--c: #{nth($c, 4)}
}
g.meas { transform: scaley(var(--sgn-a)) }
.arc {
r: var(--r-arc);
stroke-dasharray: calc(var(--abs-a)*1px) 360px;
}
.arr {
transform:
rotate(calc(var(--sgn-a)*var(--ang-a)))
translate(var(--r-arc));
opacity: var(--a-cut);
stroke-linejoin: round
}
[x2] { transform: var(--mov) scalex(calc(var(--rf)*var(--cos))) }
[y2] { transform: var(--mov) scaley(calc(var(--rf)*var(--sin))) }
.guide {
--c: #d7d7d7;
&[x2] { --mov: translatey(calc(var(--y)*1px)) }
&[y2] { --mov: translatex(calc(var(--x)*1px)) }
}
.proj { --c: #{nth($c, 1)} }
.rad { --c: #{nth($c, 3)} }
line.proj { --sm: .008px }
line.rad {
transform: rotate(calc(var(--a)*1deg)) scalex(var(--rf));
}
.main {
--c: #{nth($c, 2)};
--sm: .006px;
r: calc(var(--r)*1px)
}
.point {
stroke: #140027;
&--x { cx: calc(var(--x)*1px) }
&--y { cy: calc(var(--y)*1px) }
}
foreignObject {
--h: 1.5em;
position: relative;
x: calc(-.5*var(--w));
y: calc(-.5*var(--h));
width: var(--w);
height: var(--h);
&.meas {
--w: 6ch;
--a-cut: clamp(0, calc(var(--abs-a) - 39), 1);
--r-cut: clamp(0, calc(var(--r) - 325), 1);
--flag: Min(1, calc(var(--a-cut) + var(--r-cut)));
transform:
rotate(calc(.5*var(--ang-a)))
translate(calc(var(--flag)*(var(--r-arc) + .325*(var(--w) + var(--h))) + (1 - var(--flag))*.4375*var(--r-arc)))
rotate(calc(-.5*var(--ang-a)));
}
&.rad {
--w: 4ch;
transform:
rotate(calc(var(--ang-a)))
translate(calc(var(--r)*.75px))
rotate(calc(-1*var(--ang-a)));
}
&.cart {
--c: #{nth($c, 1)};
--w: 10ch;
transform:
rotate(calc(var(--ang-a)))
translate(calc(var(--r)*1px + .375*(var(--w) + var(--h))))
rotate(calc(-1*var(--ang-a)));
opacity: var(--s);
output {
counter-reset: x var(--x) y var(--y);
&::before { content: counter(x) ',' counter(y) }
}
}
output {
position: absolute;
top: 50%; left: 50%;
padding: 0 2px 2px;
transform: translate(-50%, -50%);
background: var(--c);
}
}
/* --------------- CODE --------------- */
pre {
display: grid;
place-content: center;
white-space: normal
}
.token {
&--form { display: flex }
&--var { color: mix(nth($c, 2), #fff) }
&--func { color: mix(nth($c, 5), #fff) }
&--len { color: mix(nth($c, 3), #fff) }
&--ang { color: mix(nth($c, 4), #fff) }
&--coord { color: mix(nth($c, 1), #fff) }
&--oper:first-of-type, &--punc + &--oper {
&::before, &::after {
white-space: pre;
content: ' '
}
}
&--oper:last-of-type, &--coord { opacity: var(--s) }
}
View Compiled
document.documentElement.classList.add('js')
const S = document.body.style;
addEventListener('input', e => {
let _t = e.target, id = _t.id, val = +_t.value;
S.setProperty(`--${id}`, val);
if(id === 'a') {
let rad = val*Math.PI/180;
S.setProperty(`--cos`, +Math.cos(rad).toFixed(3));
S.setProperty(`--sin`, +Math.sin(rad).toFixed(3));
}
}, false)
View Compiled
This Pen doesn't use any external CSS resources.