A Pen by not important on CodePen.
Created
January 28, 2017 20:31
-
-
Save clindsey/e8eb4ed6729218f78843a1c1f6533a71 to your computer and use it in GitHub Desktop.
triangle-nest-1.0.0
This file contains 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
<canvas | |
id="js-canvas" | |
height="410" | |
width="480" | |
></canvas> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.4.4/randomColor.min.js"></script> |
This file contains 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
setTimeout(() => { | |
const canvasEl = document.getElementById('js-canvas'); | |
const $ = canvasEl.getContext('2d'); | |
const { | |
width, | |
height | |
} = canvasEl; | |
const centerX = width / 2; | |
const centerY = height / 2; | |
const radius = Math.min(width, height) / 2; | |
const pointsUp = buildPoints(3, Math.PI * 1.5); | |
const pointsDown = buildPoints(3, Math.PI * 0.5); | |
const colors = ['0000ff', '00ff00', 'ff0000']; | |
const colorPoints = pointsUp.map(([x, y]) => ({color: colors.pop(), x: x * radius + centerX, y: y * radius + centerY})); | |
const colorPicker = calculateColor(colorPoints, radius); | |
triangleNest($, centerX, centerY, radius, [pointsDown, pointsUp], colorPicker, 3); | |
}, 0); | |
function triangleNest ($, x, y, radius, [centerPoints, outerPoints], colorPicker, iteration) { | |
const newRadius = radius / 2; | |
if (!iteration) { | |
drawPolygon($, x, y, newRadius, centerPoints, colorPicker(x, y)); | |
} else { | |
triangleNest($, x, y, newRadius, [outerPoints, centerPoints], colorPicker, iteration - 1); | |
} | |
outerPoints.forEach(([pointX, pointY], edgeIndex) => { | |
const newX = pointX * newRadius + x; | |
const newY = pointY * newRadius + y; | |
if (!iteration) { | |
drawPolygon($, newX, newY, newRadius, outerPoints, colorPicker(newX, newY)); | |
} else { | |
triangleNest($, newX, newY, newRadius, [centerPoints, outerPoints], colorPicker, iteration - 1); | |
} | |
}); | |
} | |
function calculateColor (colorPoints, radius) { | |
const maxRadius = radius * 1.6783; // refactor, magic number | |
const colorFactors = colorPoints.map(({color, x, y}) => { | |
const colorInt = parseInt(color, 16); | |
return { | |
x, | |
y, | |
r: colorInt >> 16 & 0xff, | |
g: colorInt >> 8 & 0xff, | |
b: colorInt >> 0 & 0xff | |
}; | |
}); | |
const pointA = [colorFactors[0].x, colorFactors[0].y]; | |
const pointB = [colorFactors[1].x, colorFactors[1].y]; | |
const pointC = [colorFactors[2].x, colorFactors[2].y]; | |
const totalArea = measureArea(pointA, pointB, pointC); | |
return (pointX, pointY) => { | |
const pointD = [pointX, pointY]; | |
const factorA = measureArea(pointA, pointB, pointD) / totalArea; | |
const factorB = measureArea(pointB, pointC, pointD) / totalArea; | |
const factorC = 1 - (factorA + factorB) | |
const r = (colorFactors[0].r * factorA) + (colorFactors[1].r * factorB) + (colorFactors[2].r * factorC); | |
const g = (colorFactors[0].g * factorA) + (colorFactors[1].g * factorB) + (colorFactors[2].g * factorC); | |
const b = (colorFactors[0].b * factorA) + (colorFactors[1].b * factorB) + (colorFactors[2].b * factorC); | |
return '#' + ((b | g << 8 | r << 16) | 0x1000000).toString(16).substring(1); | |
}; | |
} | |
function measureArea (pointA, pointB, pointC) { | |
const side1 = measureDistance(pointA, pointB); | |
const side2 = measureDistance(pointB, pointC); | |
const side3 = measureDistance(pointC, pointA); | |
const perimeter = (side1 + side2 + side3) / 2; | |
return Math.sqrt(perimeter * ((perimeter - side1) * (perimeter - side2) * (perimeter - side3))); | |
} | |
function measureDistance ([x1, y1], [x2, y2]) { | |
return Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))); | |
} | |
function drawPolygon ($, x, y, radius, [firstPoint, ...otherPoints], color) { | |
$.lineWidth = 1; | |
$.strokeStyle = color; | |
$.fillStyle = color; | |
$.beginPath(); | |
$.moveTo(x + firstPoint[0] * radius, y + firstPoint[1] * radius); | |
[...otherPoints, firstPoint].forEach(nextPoint => { | |
$.lineTo(x + nextPoint[0] * radius, y + nextPoint[1] * radius); | |
}); | |
$.fill(); | |
$.stroke(); | |
} | |
function buildPoints (edgeCount, rotationOffset = 0) { | |
const stepSize = (Math.PI * 2) / edgeCount; | |
return Array(...(new Array(edgeCount))).map((_, edgeIndex) => [ | |
Math.cos(edgeIndex * stepSize + rotationOffset), | |
Math.sin(edgeIndex * stepSize + rotationOffset) | |
]); | |
} |
This file contains 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
canvas { | |
display: block; | |
margin: 0 auto; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment