Skip to content

Instantly share code, notes, and snippets.

@goldhand
Last active May 2, 2016 15:54
Show Gist options
  • Save goldhand/14823f30ceadd069b0c719dfb1e9c7d9 to your computer and use it in GitHub Desktop.
Save goldhand/14823f30ceadd069b0c719dfb1e9c7d9 to your computer and use it in GitHub Desktop.
Polygon-svg
<p>Click the balls</p>
<div class="svg-container">
<svg id="svg" viewBox="0 0 100 100"></svg>
</div>
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);
.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