A Pen by Will Farley on CodePen.
Last active
May 2, 2016 15:54
-
-
Save goldhand/14823f30ceadd069b0c719dfb1e9c7d9 to your computer and use it in GitHub Desktop.
Polygon-svg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<p>Click the balls</p> | |
<div class="svg-container"> | |
<svg id="svg" viewBox="0 0 100 100"></svg> | |
</div> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let canvas = document.getElementById('svg'); | |
class Point { | |
static get(id) { | |
let obj = Path.props.objects.filter(p => p.id === id); | |
if (obj.length) return obj[0]; | |
}; | |
constructor(x, y, r = 1) { | |
this.r = r; | |
this.x = x; | |
this.y = y; | |
this.color = randomRGB(); | |
this.id = Point.props.counter += 1; | |
Point.props.objects.push(this); | |
} | |
draw() { | |
canvas.appendChild(this.elem); | |
} | |
build() { | |
this.elem = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); | |
this.elem.setAttribute('class', 'circle'); | |
this.elem.setAttribute('cx', this.x); | |
this.elem.setAttribute('cy', this.y); | |
this.elem.setAttribute('r', this.r); | |
this.elem.setAttribute('fill', this.color); | |
this.setListener_(); | |
} | |
setListener_() { | |
this.elem.addEventListener('click', () => { | |
let path = Path.get(Point.props.next); | |
if (path.id <= this.id) { | |
path.activateUntil(this.id); | |
Point.props.next = this.id + 1; | |
} | |
}); | |
} | |
slope(point) { | |
// return slope from this original point to another point | |
return (point.y - this.y) / | |
(point.x - this.x); | |
} | |
angle(point) { | |
let rads = Math.atan(this.slope(point)); // arc tangent radians | |
return degrees(rads); | |
} | |
distance(point) { | |
// return distance from this original point to another point | |
let | |
m = this.slope(point), | |
dy = point.y - this.y, | |
dx = point.x - this.x; | |
// Pythagorean Theorem | |
return Math.sqrt( | |
(dx * dx) + (dy * dy) | |
); | |
} | |
} | |
Point.props = { | |
objects: [], | |
counter: 0, | |
next: 1 | |
}; | |
class Path { | |
static get(id) { | |
let obj = Path.props.objects.filter(p => p.id === id); | |
if (obj.length) return obj[0]; | |
}; | |
constructor(...args) { | |
this.points = args; | |
this.start = args[0]; | |
this.end = args[args.length - 1]; | |
this.id = Point.props.counter += 1; | |
this.color = this.end.color; | |
Path.props.objects.push(this); | |
} | |
build(dash = true, close = false) { | |
this.elem = document.createElementNS('http://www.w3.org/2000/svg', 'path'); | |
this.elem.setAttribute('class', 'path'); | |
this.elem.setAttribute('d', this.path(close)); | |
this.elem.setAttribute('fill', 'transparent'); | |
this.elem.setAttribute('stroke', this.color); | |
// hide until active | |
if (dash) this.setDash(); | |
} | |
draw() { | |
canvas.appendChild(this.elem); | |
} | |
path(close) { | |
let | |
{points} = this, | |
start = points.shift(); | |
if (close) { | |
points.push(start); | |
} | |
return points.reduce((pv, cv) => { | |
return `${pv}L${cv.x},${cv.y}`; | |
}, `M${this.start.x},${this.start.y}`); | |
//return `M${start.x},${start.y}L${end.x},${end.y}`; | |
} | |
setDash() { | |
let length = this.elem.getTotalLength(); | |
this.elem.style.strokeDasharray = length; | |
this.elem.style.strokeDashoffset = length; | |
} | |
activate() { | |
this.elem.classList.add('active'); | |
} | |
activateUntil(end, timeout = 1000) { | |
this.activate(); | |
let c = this.id; | |
if (c < end) { | |
setTimeout(() => { | |
Path.get(c + 1).activateUntil(end, timeout); | |
}, timeout); | |
} | |
} | |
} | |
Path.props = { | |
objects: [], | |
counter: 0, | |
next: 1 | |
}; | |
// random color | |
function randomRGB(r = 0, g = 0, b = 0) { | |
let | |
red = r ? r : Math.round(Math.random() * 255), | |
green = g ? g : Math.round(Math.random() * 255), | |
blue = b ? b : Math.round(Math.random() * 255); | |
return `rgb(${red},${green},${blue})`; | |
} | |
// Angles | |
function radians(deg) { | |
return (Math.PI/180)*deg; | |
} | |
function degrees(rad) { | |
return rad/(Math.PI/180); | |
} | |
// Polygons | |
function polyCorner(size, i, sides, startDegree = 0, center = {x: 50, y: 50}) { | |
// calulate the corner of a polygon | |
let angle_rad = radians(360/sides * i + startDegree); | |
return new Point( | |
// calculate polygon position | |
center.x + size * Math.cos(angle_rad), | |
center.y + size * Math.sin(angle_rad) | |
) | |
} | |
function buildPolygonPoints(sides, start) { | |
let points = []; | |
for (let i = 0; i < sides; i++) { | |
let p = polyCorner(33.3, i, sides, start); | |
p.build(); | |
points.push(p); | |
} | |
return points; | |
} | |
function buildPolygonPaths(points) { | |
let paths = []; | |
for (let i = 0; i < points.length; i++) { | |
let next = points.length > i + 1 | |
? i + 1 | |
: 0; | |
let p = new Path(points[i], points[next]); | |
p.id = points[next].id; | |
p.build(); | |
paths.push(p); | |
} | |
return paths; | |
} | |
function drawObjs(points) { | |
for (let i = 0; i < points.length; i++) { | |
points[i].draw(); | |
} | |
} | |
// Main | |
//============== | |
let octagon = { | |
points: buildPolygonPoints(8, -45), | |
}, | |
square = { | |
points: buildPolygonPoints(4), | |
}; | |
octagon.outline = new Path(...octagon.points); | |
octagon.outline.color = 'rgba(100, 100, 150, .3)'; | |
octagon.outline.build(false, true); | |
octagon.outline.draw(); | |
square.outline = new Path(...square.points); | |
square.outline.color = 'rgba(100, 100, 150, .3)'; | |
square.outline.build(false, true); | |
square.outline.draw(); | |
octagon.paths = buildPolygonPaths(octagon.points); | |
drawObjs(octagon.paths); | |
drawObjs(octagon.points); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.svg-container { | |
padding-top: 100%; | |
width: 100%; | |
height: 0; | |
position: relative; | |
} | |
svg { | |
width: 100%; | |
height: 100%; | |
max-height: 800px; | |
position: absolute; | |
top: 0; | |
} | |
.path { | |
stroke-width: .3; | |
&.active { | |
animation: dash 1s linear forwards; | |
} | |
} | |
.nthloop(@counter) when (@counter > 0) { | |
.nthloop((@counter - 1)); | |
&:nth-of-type(@{counter}) { | |
animation-delay: (@counter * .1s); | |
} | |
} | |
.circle { | |
cursor: pointer; | |
animation: drift 5s linear infinite; | |
.nthloop(8); | |
} | |
@keyframes dash { | |
to { | |
stroke-dashoffset: 0; | |
} | |
} | |
@keyframes drift { | |
0% { | |
transform: translate3d(0, 0, 0); | |
} | |
20% { | |
transform: translate3d(.3px, .2px, 0); | |
} | |
40% { | |
transform: translate3d(0, .4px, 0); | |
} | |
60% { | |
transform: translate3d(-.3px, 0, 0); | |
} | |
80% { | |
transform: translate3d(.1px, -.3px, 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment