- 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

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://codepen.io/thebabydino/pen/wWMWqW.js