Skip to content

Instantly share code, notes, and snippets.

@nmattia
Last active February 24, 2020 20:59
Show Gist options
  • Save nmattia/b3baf8aea526d133137a8fe204d26c51 to your computer and use it in GitHub Desktop.
Save nmattia/b3baf8aea526d133137a8fe204d26c51 to your computer and use it in GitHub Desktop.
rotating divs
let clientX_0 = 0;
let clientX_d = 0;
const MIN_WIDTH = 10;
const MIN_HEIGHT = 10;
let w0 = getpc("inner-width");
let h0 = getpc("inner-height");
let w = w0;
let h = h0;
let p0_x = getpc("inner-left");
let p0_y = getpc("inner-top");
let r0_x = getpc("inner-left");
let r0_y = getpc("inner-top");
let p_x = p0_x;
let p_y = p0_y;
let pp_x = p0_x;
let pp_y = p0_y;
let qp0_x = p0_x + w;
let qp0_y = p0_y + h;
let q_x = qp0_x;
let q_y = qp0_y;
let qp_x = qp0_x;
let qp_y = qp0_y;
let cp_x = (q_x + p_x) / 2;
let cp_y = (q_y + p_y) / 2;
render_debug = false;
function update(name, delta) {
const reg = /(-?\d+)(.+)/;
let res = reg.exec(get(name));
let was = parseInt(res[1]);
let ext = res[2];
let new_ = was + delta;
new_ = `${new_}${ext}`;
set(name, new_);
}
function set(name, val) {
document.body.style.setProperty(`--${name}`, val);
}
function get(name) {
return window.getComputedStyle(document.body).getPropertyValue(`--${name}`);
}
function getpx(name) {
const reg = /(-?\d+)px/;
let res = reg.exec(get(name));
return parseInt(res[1]);
}
function getpc(name) {
const reg = /(-?\d+)%/;
let res = reg.exec(get(name));
return parseInt(res[1]);
}
function setpc(name, val) {
set(name, `${val}%`);
}
function getdeg(name) {
const reg = /(-?\d+)deg/;
let res = reg.exec(get(name));
return parseInt(res[1]);
}
function render() {
if (render_debug) {
// document.getElementById("logs").innerHTML = `
// clientX_0: ${clientX_0} <br/>
// clientX_d: ${clientX_d} <br/><br/>
// theta: ${get("theta")} <br/>
// inner-left: ${get("inner-left")}<br/>
// inner-top: ${get("inner-top")}<br/>
// p_0 = (${p0_x}, ${p0_y})<br/>
// p = (${p_x}, ${p_y})<br/>
// p' = (${pp_x}, ${pp_y})<br/><br/>
// q = (${q_x}, ${q_y})<br/>
// q'_0 = (${qp0_x}, ${qp0_y})<br/>
// q' = (${qp_x}, ${qp_y})<br/><br/>
// w = ${w0} -> ${w}<br/>
// h = ${h0} -> ${h}<br/>
// w' = ${getpc("inner-width")}<br/>
// h' = ${getpc("inner-height")}<br/>
// c' = (${cp_x}, ${cp_y})
// `;
} else {
document.getElementById("logs").innerHTML = "";
}
}
render();
function onKey(e) {
switch(e.keyCode) {
case 37:
update("inner-left", -10);
break;
case 38:
update("inner-top", -10);
break;
case 39:
update("inner-left", 10);
break;
case 40:
update("inner-top", 10);
break;
}
render();
}
function onDragStart(a,b) {
const c = a === 1 ? 0 : 1;
const d = b === 1 ? 0 : 1;
return function (e){
clientX_0 = e.clientX;
clientY_0 = e.clientY;
const w0 = getpc("inner-width");
const h0 = getpc("inner-height");
let theta = getdeg("theta");
theta = Math.PI * 2 * theta / 360;
const cos_t = Math.cos(theta);
const sin_t = Math.sin(theta);
const r0_x = getpc("inner-left");
const r0_y = getpc("inner-top");
const c0_x = r0_x + w0 / 2.0;
const c0_y = r0_y + h0 / 2.0;
q0_x = r0_x + a * w0;
q0_y = r0_y + b * h0;
qp0_x = q0_x * cos_t - q0_y * sin_t - c0_x * cos_t + c0_y * sin_t + c0_x;
qp0_y = q0_x * sin_t + q0_y * cos_t - c0_x * sin_t - c0_y * cos_t + c0_y;
p0_x = r0_x + c * w0;
p0_y = r0_y + d * h0;
// pp == pp0
pp_x = p0_x * cos_t - p0_y * sin_t - c0_x * cos_t + c0_y * sin_t + c0_x;
pp_y = p0_x * sin_t + p0_y * cos_t - c0_x * sin_t - c0_y * cos_t + c0_y;
render();
}
}
function onDrag(a, b) {
const c = a === 1 ? 0 : 1;
const d = b === 1 ? 0 : 1;
return function(e) {
// silly jitter
if (e.clientX === 0 || e.clientY === 0) { return; }
clientX_d = 100 * (e.clientX - clientX_0) / getpx("outer-width");
clientY_d = 100 * (e.clientY - clientY_0) / getpx("outer-height");
const mtheta = -1 * Math.PI * 2 * getdeg("theta") / 360;
const cos_mt = Math.cos(mtheta);
const sin_mt = Math.sin(mtheta);
qp_x = qp0_x + clientX_d;
qp_y = qp0_y + clientY_d;
cp_x = (qp_x + pp_x) / 2.0;
cp_y = (qp_y + pp_y) / 2.0;
q_x = qp_x * cos_mt - qp_y * sin_mt - cos_mt * cp_x + sin_mt * cp_y + cp_x;
q_y = qp_x * sin_mt + qp_y * cos_mt - sin_mt * cp_x - cos_mt * cp_y + cp_y;
p_x = pp_x * cos_mt - pp_y * sin_mt - cos_mt * cp_x + sin_mt * cp_y + cp_x;
p_y = pp_x * sin_mt + pp_y * cos_mt - sin_mt * cp_x - cos_mt * cp_y + cp_y;
const wtmp = a * (q_x - p_x) + c * (p_x - q_x);
const htmp = b * (q_y - p_y) + d * (p_y - q_y);
if (wtmp < MIN_WIDTH || htmp < MIN_HEIGHT) {
w = Math.max(MIN_WIDTH, wtmp);
h = Math.max(MIN_HEIGHT, htmp);
const theta = -1 * mtheta;
cos_t = Math.cos(theta);
sin_t = Math.sin(theta);
let dh_x = - sin_t * h;
let dh_y = cos_t * h;
let dw_x = cos_t * w;
let dw_y = sin_t * w;
qp_x = pp_x + (a - c) * dw_x + (b - d) * dh_x
qp_y = pp_y + (a - c) * dw_y + (b - d) * dh_y
cp_x = (qp_x + pp_x) / 2.0;
cp_y = (qp_y + pp_y) / 2.0;
q_x = qp_x * cos_mt - qp_y * sin_mt - cos_mt * cp_x + sin_mt * cp_y + cp_x;
q_y = qp_x * sin_mt + qp_y * cos_mt - sin_mt * cp_x - cos_mt * cp_y + cp_y;
p_x = pp_x * cos_mt - pp_y * sin_mt - cos_mt * cp_x + sin_mt * cp_y + cp_x;
p_y = pp_x * sin_mt + pp_y * cos_mt - sin_mt * cp_x - cos_mt * cp_y + cp_y;
} else {
w = wtmp;
h = htmp;
}
const r_x = c * q_x + a * p_x;
const r_y = d * q_y + b * p_y;
setpc("inner-left", r_x);
setpc("inner-top", r_y);
setpc("inner-width", w);
setpc("inner-height", h);
render();
}
}
function onDragEnd(xf,yf) {
return function(e) {
clientX_d = clientX_0 = 0;
clientY_d = clientY_0 = 0;
setpc("inner-left", r0_x);
setpc("inner-top", r0_y);
setpc("inner-width", w0);
setpc("inner-height", h0);
render();
}
}
window.onkeydown = onKey;
document.getElementById("bottomright").ondrag = onDrag(1,1);
document.getElementById("bottomright").ondragstart = onDragStart(1,1);
document.getElementById("bottomright").ondragend = onDragEnd(1,1);
document.getElementById("bottomleft").ondrag = onDrag(0,1);
document.getElementById("bottomleft").ondragstart = onDragStart(0,1);
document.getElementById("bottomleft").ondragend = onDragEnd(0,1);
document.getElementById("topleft").ondrag = onDrag(0,0);
document.getElementById("topleft").ondragstart = onDragStart(0,0);
document.getElementById("topleft").ondragend = onDragEnd(0,0);
document.getElementById("topright").ondrag = onDrag(1,0);
document.getElementById("topright").ondragstart = onDragStart(1,0);
document.getElementById("topright").ondragend = onDragEnd(1,0);
<head>
<style>
body {
background-color: linen;
}
h1 {
color: maroon;
margin-left: 40px;
}
:root {
--outer-top: 250px;
--outer-left: 250px;
--outer-width: 500px;
--outer-height: 500px;
--inner-width: 50%;
--inner-height: 50%;
--inner-left: -25%;
--inner-top: -25%;
--corner-radius: 20px;
--theta: 25deg;
}
#outer {
position: relative;
width: var(--outer-width);
height: var(--outer-height);
top: var(--outer-top);
left: var(--outer-left);
border: solid lightgray 2px;
}
#inner {
position: absolute;
width: var(--inner-width);
height: var(--inner-height);
top: var(--inner-top);
left: var(--inner-left);
border: solid black 2px;
transform: rotate(var(--theta));
}
.corner {
position: absolute;
width: 20px;
height: 20px;
border: solid black 2px;
border-radius: 20px;
}
#bottomright{
top: calc( 100% - var(--corner-radius) / 2);
left: calc( 100% - var(--corner-radius) / 2);
}
#bottomleft{
top: calc( 100% - var(--corner-radius) / 2);
left: calc( 0% - var(--corner-radius) / 2);
}
#topright{
top: calc( 0px - var(--corner-radius) / 2);
left: calc( 100% - var(--corner-radius) / 2);
}
#topleft{
top: calc( 0% - var(--corner-radius) / 2);
left: calc( 0% - var(--corner-radius) / 2);
}
</style>
</head>
<div id="outer">
<div id="inner" draggable="true">
<div id="bottomright" class="corner" draggable="true"></div>
<div id="bottomleft" class="corner" draggable="true"></div>
<div id="topright" class="corner" draggable="true"></div>
<div id="topleft" class="corner" draggable="true"></div>
</div>
</div>
<div id="logs">
</div>
<script src="./foo.js"></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment