- var d = 5000, o = -.5*d;

//- axes
//- how much axes extend
- var ax_e = .45*d;
//- axis arrow marker dims
- var mrk_h = .015*d, mrk_w = 1.5*mrk_h;
//- axis label offset
- var ax_t = .475*d;

//- main circle
- var r = .35*d, fr = Math.round(.1*r);

//- generic point
- var pt_r = .004*d;

//- start angle
- var sa_deg = Math.round(20 + 50*Math.random());
- var sa_rad = sa_deg/180*Math.PI;
- var xp = Math.round(r*Math.cos(sa_rad));
- var yp = Math.round(r*Math.sin(sa_rad));
- var fxp = Math.round(.1*xp);
- var fyp = Math.round(.1*yp);

//- angular measure
- var me_r = .32*r, met_r = .75*me_r;
- var xm = Math.round(me_r*Math.cos(sa_rad));
- var ym = Math.round(me_r*Math.sin(sa_rad));
- var xmt = Math.round(met_r*Math.cos(.5*sa_rad));
- var ymt = Math.round(met_r*Math.sin(.5*sa_rad));

svg(viewBox=[o, o, d, d].join(' ') 
		aria-labelledby='title descr' role='img')
	title#title interactive demo explaining position of point in a plane
	descr#descr The position of a point in a plane is described by either its cartesian coordinates (x,y) or its polar coordinates (r,t)
	defs
		marker#arr0(viewBox='-50 -70 250 140' 
								markerWidth=mrk_w 
								markerHeight=mrk_h
								orient='auto' refX='100')
			path#ap(d='M50,0L0-50L150,0L0,50z')
		marker#arr1(viewBox='-50 -70 250 140' 
								markerWidth=mrk_w
								markerHeight=mrk_h
								orient='auto' refX='105')
			use(xlink:href='#ap' transform='scale(.7)')
		circle#point(r=pt_r)
	
	g#ang-meas
		path#arc.arr(d=`M0,0h${me_r}A${[me_r, me_r, 0, 0, 1, xm, ym]}` marker-end='none')
		text#ta.c.dvm.dhm(x=xmt y=ymt) #{sa_deg}°
	
	g#coord-syst
		path#ax(d=`M-${ax_e},0H${ax_e}` 
						marker-end='url(#arr0)')
		text.dhm.dvm(x=ax_t) x
		use(xlink:href='#ax' 
				transform='rotate(90)')
		text.dhm.dvm(y=ax_t) y
	
	circle#circ(r=r)
	
	g#guides
		path#gx(d=`M${xp},0v${yp}`)
		path#gy(d=`M0,${yp}h${xp}`)
	
	g#projections
		line#px(x2=xp)
		use#fx(xlink:href='#point' x=xp)
		text#tx.c.dhm(x=.5*xp y=-pt_r) #{fxp}
		line#py(y2=yp)
		use#fy(xlink:href='#point' y=yp)
		text#ty.c.dvm.dh1(x=-pt_r y=.5*yp) #{fyp}
	
	g#radius
		text#tp.dv0(x=(xp + pt_r) y=(yp + pt_r)) P<tspan class='c' id='coord'>(#{fxp},#{fyp})</tspan>
		g#rotor(transform=`rotate(${sa_deg})`)
			line#rl(x2=r)
			circle#rp(r=1.5*pt_r cx=r)
			use(xlink:href='#rp' opacity='0')
		text#tr.c(x=.5*xp y=.5*yp) #{fr}
	
	g
		use(xlink:href='#point')
		text#orig.dh1(x=-pt_r y=-pt_r) O<tspan class='c'>(0,0)</tspan>

code
	.l <var>x</var> = r·cos(θ) = 
		span#cx #{fr}·cos(#{sa_deg}°) = #{fxp}
	.l <var>y</var> = r·sin(θ) = 
		span#cy #{fr}·sin(#{sa_deg}°) = #{fyp}
View Compiled
* { margin: 0; padding: 0; }

body {
	display: flex;
	flex-direction: column;
	margin: 0;
	height: 100vh;
}

svg { flex: 1; }

line, circle, path {
	stroke: currentColor;
	vector-effect: non-scaling-stroke;
}

text {
	fill: currentColor;
	font: 700 italic 7rem serif;
}

code {
	background: rgba(#000, .875);
	color: #fff;
	font: 1.125em/1.5 courier, monospace;
	text-align: center;
}

var { font-family: times new roman, serif; }

.drag { user-select: none; }

.c { font: 700 7rem courier, monospace; }

.dh1 { text-anchor: end; }
.dv0 { dominant-baseline: hanging; }
.dhm { text-anchor: middle; }
.dvm { dominant-baseline: middle; }

.arr { marker-end: url(#arr1); }

[id='arc'] {
	fill: none;
	color: #ef3491;
	stroke-width: 2px;
}

[id='ta'] { fill: #ef3491; }

[id='coord-syst'], [id='arr0'], [id='orig'], 
[id='guides'] {
	color: #ccd;
}

[id='arr0'] { fill: currentcolor; }

[id='arr1'] {
	color: #ef3491;
	fill: currentcolor
}

[id='ax'] { stroke-width: 2px; }

[id='circ'] {
	fill: none;
	color: #800040;
	stroke-width: 2px;
}

[id='projections'] {
	color: #804000;
	
	line { stroke-width: 3px; }
}

[id='rotor'] {
	cursor: pointer;
	stroke-width: 2px;
}

[id='rl'] {
	color: #ef9134;
	stroke-width: 4px;
}

[id='tr'] {
	fill: #000;
	stroke: #eec7a0;
	stroke-width: 2px;
	font-size: 8rem;
}

[id='rp'] {
	color: #9134ef;
	fill: #c7a0ee;
	
	+ use { stroke-width: 25px; }
}

[id='tr'] {
	text-anchor: middle;
	dominant-baseline: middle;
}

[id='tp'] {
	color: #400080;
	pointer-events: none;
}
const _SVG = $$('svg'), 
			D = _SVG._attr('viewBox').split(' ')[2], 
			O = -.5*D, 
			MIN_R = .125*D, MAX_R = .365*D, 
			RP = $$('#point')._attr('r'), 
			_VE = {}, 
			CF = 180/PI;

let f, ox, oy, drag = false;

let size = function() {
	let dh, r = _SVG.getBoundingClientRect();
	
	f = D/min(r.width, r.height);
	dh = .5*abs(r.width - r.height);
	ox = r.width > r.height ? dh : 0;
	oy = r.width > r.height ? 0 : dh;
};

let getE = function(ev) {
	return ev.touches ? ev.touches[0] : ev;
};

let lock = function(ev) {
	let e = getE(ev), 
			t = e.target.correspondingUseElement || 
					e.target;
		
	if(t.parentNode === _VE.rotor) {
		drag = true;
		$.body.classList.add('drag');
	}
};

let act = function(ev) {
	if(drag) {
		let e = getE(ev), 
				x = O + f*(e.clientX - ox), 
				y = O + f*(e.clientY - oy), 
				ρ = min(MAX_R, 
								max(MIN_R, hypot(x, y))), 
				θ = atan2(y, x), t = CF*θ, 
				xs, ys, rs, ts, tx, ty, 
				mr = max(.32*ρ, .2*MIN_R), 
				s = sign(θ), s1 = sign(cos(θ)), 
				c = .5*(1 + s), 
				mx = mr*cos(θ), my = mr*sin(θ), 
				ar = .65*mr, ax, ay, 
				aa = s*.5*min(.5*PI, abs(θ));
		
		
		x = ρ*cos(θ);
		y = ρ*sin(θ);
		xs = round(.1*x);
		ys = round(.1*y);
		rs = round(.1*ρ);
		ts = round(t);
		tx = s1*max(.5*abs(x), .025*D);
		ty = s*max(.5*abs(y), .025*D);
		
		if(abs(ty) < mr && s1 < 0) ar = 1.35*mr;
		if((abs(x) < mr && s1 > 0) || 
			 (ρ < .2*D) || 
			 (abs(ts) < 15 && abs(ts) > 5)) 
			ar = ρ + .35*MIN_R;
		
		ax = ar*cos(aa);
		ay = ar*sin(aa);
		
		if(abs(ts) <= 5) {
			ay = -s*RP;
			
			if(_VE.ta.classList.contains('dvm')) {
				_VE.ta.classList.remove('dvm');
			}
			
			if(s < 0)
				_VE.ta.classList.add('dv0');
			else
				_VE.ta.classList.remove('dv0');
		} else 			
			if(!_VE.ta.classList.contains('dvm')) {
				_VE.ta.classList.add('dvm')
			}
		
		if(abs(t) > 90 && 
			 _VE.orig.classList.contains('dh1')) {
			_VE.orig.classList.remove('dh1');
			_VE.orig._attr({'x': RP});
			_VE.tp.classList.add('dh1');
			_VE.ty.classList.remove('dh1');
			_VE.ty._attr({'x': RP});
		} else if(abs(t) <= 90 && 
			 !_VE.orig.classList.contains('dh1')) {
			_VE.orig.classList.add('dh1');
			_VE.orig._attr({'x': -RP});
			_VE.tp.classList.remove('dh1');
			_VE.ty.classList.add('dh1');
			_VE.ty._attr({'x': -RP});
		}
		
		if(s < 0 && 
			 !_VE.orig.classList.contains('dv0')) {
			_VE.orig.classList.add('dv0');
			_VE.orig._attr({'y': RP});
			_VE.tp.classList.remove('dv0');
			_VE.tx.classList.add('dv0');
			_VE.tx._attr({'y': RP});
		} else if(s > 0 && 
			 _VE.orig.classList.contains('dv0')) {
			_VE.orig.classList.remove('dv0');
			_VE.orig._attr({'y': -RP});
			_VE.tp.classList.add('dv0');
			_VE.tx.classList.remove('dv0');
			_VE.tx._attr({'y': -RP});
		}
				
		_VE.circ._attr({'r': ρ});
		
		_VE.arc._attr({
			'd':
			t ? 
			`M0,0h${mr}A${[mr,mr,0,0,c,mx,my]}` : 
			'M0,0'
		});
		
		if(_VE.arc.getTotalLength() < .14*D && 
			 ts < 30) {
				_VE.arc.classList.remove('arr');
		} else _VE.arc.classList.add('arr');
		
		if(ts) {
			_VE.ta._attr({'x': ax, 'y': ay});
			_VE.ta.textContent = `${ts}°`;
		} else _VE.ta.textContent = '';
		
		_VE.rotor._attr({
			'transform': `rotate(${round(t)})`
		});
		
		_VE.rl._attr({'x2': ρ});
		_VE.rp._attr({'cx': ρ});
		
		_VE.tp._attr({
			'x': x + (s1 || 1)*RP, 
			'y': y + (s || 1)*RP
		});
		
		_VE.coord.textContent = `(${xs},${ys})`;
		
		if(abs(xs) > 20 && abs(ys) > 10) {
			_VE.tr._attr({'x': .5*x, 'y': .5*y});
			_VE.tr.textContent = rs;
		} else _VE.tr.textContent = '';
		
		_VE.px._attr({'x2': x});
		_VE.fx._attr({'x': x});
		
		if(xs) {
			_VE.tx._attr({'x': tx});
			_VE.tx.textContent = xs;
		}
		else _VE.tx.textContent = '';
		
		_VE.gx._attr({'d': `M${x},0v${y}`});
		
		_VE.cx.textContent = 
			`${rs}·cos(${ts}°) = ${xs}`
		
		_VE.py._attr({'y2': y});
		_VE.fy._attr({'y': y});
		
		if(ys) {
			_VE.ty._attr({'y': ty});
			_VE.ty.textContent = ys;
		}
		else _VE.ty.textContent = '';
		
		_VE.gy._attr({'d': `M0,${y}h${x}`});
		
		_VE.cy.textContent = 
			`${rs}·sin(${ts}°) = ${ys}`
	}
};

let release = function(e) {
	if(drag) {
		drag = false;
		$.body.classList.remove('drag');
	}
};

(function init() {
	let ids = ['orig', 'circ', 'arc', 'ta', 
						 'rotor', 'rl', 'rp', 
						 'tp', 'coord', 'tr', 
						 'px', 'fx', 'tx', 'gx', 'cx', 
						 'py', 'fy', 'ty', 'gy', 'cy'], 
			nids = ids.length;
	
	for(let i = 0; i < nids; i++)
		_VE[ids[i]] = $$(`#${ids[i]}`);
	
	size();
})();

addEventListener('resize', size, false);

addEventListener('mousedown', lock, false);
addEventListener('touchstart', lock, false);

addEventListener('mousemove', act, false);
addEventListener('touchmove', act, false);

addEventListener('mouseup', release, false);
addEventListener('touchend', release, false);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

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