JSFiddle - React, Tailwind, and code Playground

by Andrey Bazykin

HTML

<div class="ellipse ellipse-1"></div>
<div class="ellipse ellipse-2" data-rotate="30deg"></div>
<div class="ellipse ellipse-3" data-rotate="60deg*"></div>

CSS

body{
	margin:20px;
}
.ellipse{
	display:inline-block;
	position:relative;
	width:200px;
	height:300px;
	margin:30px;
	background:#f0f0f0;
}
.ellipse .inner{
	content:"";
	position:absolute;
	top:0;
	right:0;
	bottom:0;
	left:0;
	border:2px solid #666;
	border-radius:100px/150px;
}
.ellipse .dot{
	position:absolute;
	width:20px;
	height:20px;
	margin:-10px 0 0 -10px;
	border-radius:100%;
	background:#000;
	transform-origin:50% 50%;
}
.ellipse:hover .dot{
	background:#f00;
}

JavaScript

$(function () {
	$('.ellipse').each(function () {
		var $item = $(this),
			$inner = $('<div class="inner">').appendTo($item),
			$dot = $('<div class="dot">').appendTo($item),
			dims = {
				W: this.clientWidth,
				H: this.clientHeight
			},
			center = {
				X: dims.W / 2,
				Y: dims.H / 2
			},
			ratio = dims.W / dims.H,
			rotate = $item.data('rotate'),
			angle = 0,
			start = 0,
			time = [20, 5],
			interval = time[0],
			process;

		$item
		.on('mouseenter', function () {
			interval = time[1];
		})
		.on('mouseleave', function () {
			interval = time[0];
		})
		.on('mousedown', function () {
			clearTimeout(process);
		})
		.on('mouseup', function () {
			animation();
		});

		if (rotate) {
			rotate = rotate.split('*');

			if (rotate[1] !== undefined) {
				angle = Math.PI * parseInt(rotate[0]) / 180;
				$inner.css({
					transform: 'rotateZ(' + rotate[0] + ')'
				});
			} else {
				$item.css({
					transform: 'rotateZ(' + rotate[0] + ')'
				});
			}
		}

		animation();

		function animation() {
			var x = center.X * Math.sin(start),
				y = center.Y * Math.cos(start),
				X = x * Math.cos(angle) - y * Math.sin(angle),
				Y = x * Math.sin(angle) + y * Math.cos(angle);

			$dot.css({
				top: center.Y + Y,
				left: center.X + X
			});
			start += .02;

			process = setTimeout(animation, interval);
		}
	});
});