Move mouse to let the form evolve. Click New to start from a new form.
A Pen by Sten Hougaard on CodePen.
<div class="_controls hidden"><button class="_new">New</button> | |
<span style="pointer-events: none">Move mouse to let the form evolve.<br>Click New to start from a new form.</span></div> | |
<svg width="100%" height="100%" class="_svg"> | |
<g class="_g"></g> | |
</svg> |
Move mouse to let the form evolve. Click New to start from a new form.
A Pen by Sten Hougaard on CodePen.
Array.from(document.body.querySelectorAll('[class^="_"]')).map(ele => { | |
Array.from(ele.classList).map(sClass => { | |
var name = "_" + sClass.replace(/[-]/gi, ""); | |
if (typeof window[name] === "undefined") { | |
window[name] = ele; | |
} else { | |
window[name] = [window[name]]; | |
window[name].push(ele); | |
} | |
}); | |
}); | |
function getPoint(cx, cy, r, a) { | |
var aa = Math.radians(a); | |
let x = Math.cos(aa) * r + cx; | |
let y = Math.sin(aa) * r + cy; | |
return `${x} ${y}`; | |
} | |
// Converts from degrees to radians. | |
Math.radians = function(degrees) { | |
return degrees * Math.PI / 180; | |
}; | |
// Converts from radians to degrees. | |
Math.degrees = function(radians) { | |
return radians * 180 / Math.PI; | |
}; | |
// Credits goes to Stackoverflow: http://stackoverflow.com/a/14413632 | |
function getAngleFromPoint(point, centerPoint) { | |
var dy = (point.Y - centerPoint.Y), | |
dx = (point.X - centerPoint.X); | |
var theta = Math.atan2(dy, dx); | |
var angle = (((theta * 180) / Math.PI)) % 360; | |
angle = (angle<0) ? 360+angle : angle; | |
return angle; | |
} | |
// Credits goes to http://snipplr.com/view/47207/ | |
function getDistance( point1, point2 ) | |
{ | |
var xs = 0; | |
var ys = 0; | |
xs = point2.X - point1.X; | |
xs = xs * xs; | |
ys = point2.Y - point1.Y; | |
ys = ys * ys; | |
return Math.sqrt( xs + ys ); | |
} | |
function addLines() { | |
let d = ''; | |
for(var p=0; p<noOfPoints; p++) { | |
d+=(p==0 ? 'M ' : ' ')+getPoint(cx, cy, r, points[p].a)+(p==0 ? ' L ' : ' '); | |
} | |
s += Math.abs(as) % 360; | |
h += Math.abs(ah) % 100; | |
l += Math.abs(al) % 100; | |
a += Math.abs(aa) % 1; | |
__g.innerHTML+=`<path d="${d}" stroke="hsla(${h},${s}%,${l}%,${a})" stroke-width="1" />` | |
} | |
function render(keep) { | |
if (!keep) { | |
h = parseInt(Math.random()*360); | |
s = parseInt(Math.random()*100); | |
l = parseInt(Math.random()*100); | |
a = Math.random()*.25+.5; | |
__svg.style.backgroundColor = `hsla(${h},0%,${100-l}%,1)` | |
ah = Math.random()-Math.random(); | |
as = Math.random()-Math.random(); | |
al = Math.random()-Math.random(); | |
aa = (Math.random()-Math.random())/120; | |
const cs = getComputedStyle(__svg); | |
width = parseInt(cs.width); | |
height = parseInt(cs.height); | |
r = (Math.min(width, height) / 2-100) * Math.random() + 100; | |
cx = r+(width-r*2)/2; | |
cy = r+(height-r*2)/2; | |
__g.innerHTML = ''; | |
points = []; | |
for(var p=0; p<noOfPoints; p++) { | |
points.push({a:parseInt(Math.random()*360), da: Math.random()-Math.random()*10}) | |
} | |
} | |
for(var i=0; i<10; i++) { | |
addLines(); | |
for(var p=0; p<noOfPoints; p++) { | |
points[p].a += points[p].da; | |
} | |
} | |
} | |
let cx, cy, r, width, height, points; | |
let h,s,l,a; | |
let ah,as,al,aa; | |
let noOfPoints = 2; | |
render(false); | |
['mousemove', 'touchmove'].forEach(evtname => { | |
document.body.addEventListener(evtname, (evt) => { | |
evt.preventDefault(); | |
render(true); | |
}); | |
}) | |
__new.addEventListener('click', (evt) => { | |
evt.preventDefault(); | |
render(false); | |
}); | |
__controls.addEventListener('mouseleave', () => __controls.classList.add('hidden')); | |
__controls.addEventListener('mouseenter', () => __controls.classList.remove('hidden')); |
html, body { | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
height: 100%; | |
} | |
svg { | |
width: 100%; | |
height: 100%; | |
} | |
.hidden { | |
opacity: .1; | |
} | |
._controls { | |
position: fixed; | |
bottom: 0; | |
right: 0; | |
display: flex; | |
flex-direction: column; | |
justify-content: flex-end; | |
background: hsla(0,0%,90%,.6); | |
padding: 10px; | |
border-radius: 15px 0 0 0; | |
font-family: sans-serif; | |
font-weight: 100; | |
user-select: none; | |
} | |
button { | |
cursor: pointer; | |
font-size: 24pt; | |
border-radius: 7px; | |
background: hsla(0,0%,90%,.5); | |
user-select: none; | |
} | |
button, span { | |
user-select: none; | |
} |