'use strict'; /** * */ function Point(x, y, hex) { if (typeof x !== typeof 1) { throw new Error("x = " + x + " must be of type 'number'; it is currently of type '" + (typeof x) + "'."); } if (typeof y !== typeof 1) { throw new Error("y = " + y + " must be of type 'number'; it is currently of type '" + (typeof y) + "'."); } if (x < 0 || y < 0) { throw new Error("X and Y must be greater than 0."); } this.x = x; this.y = y; this.hex = hex; } /** * */ function Triangle(p1, p2, p3) { if (!(p1 instanceof Point) || !(p2 instanceof Point) || !(p3 instanceof Point)) { throw new Error("All three arguments must be of type Point."); } this.vertexA = p1; this.vertexB = p2; this.vertexC = p3; // Midpoints on each edge. this.midpointAB = this.findMidpoint(this.vertexA, this.vertexB); this.midpointAC = this.findMidpoint(this.vertexA, this.vertexC); this.midpointBC = this.findMidpoint(this.vertexB, this.vertexC); // Midpoints of segments between midpoints. this.midpointABAC = this.findMidpoint(this.midpointAB, this.midpointAC); this.midpointABBC = this.findMidpoint(this.midpointAB, this.midpointBC); this.midpointACBC = this.findMidpoint(this.midpointAC, this.midpointBC); // Paths created from a vertex and the midpoints on its two adjacent edges. this.subpathA = [this.vertexA, this.midpointAB, this.midpointAC]; this.subpathB = [this.vertexB, this.midpointAB, this.midpointBC]; this.subpathC = [this.vertexC, this.midpointAC, this.midpointBC]; } /** * */ Triangle.prototype = { /** * */ findMidpoint: function(p1, p2) { var minX = Math.min(p1.x, p2.x); var maxX = Math.max(p1.x, p2.x); var minY = Math.min(p1.y, p2.y); var maxY = Math.max(p1.y, p2.y); var midX = minX + ((maxX - minX) / 2); var midY = minY + ((maxY - minY) / 2); return new Point(midX, midY); }, /** * */ buildPath: function(p1, p2, p3, fill) { var path = d3.select(document.createElementNS(d3.ns.prefix.svg, "path")) .attr("d", `M${p1.x},${p1.y} L${p2.x},${p2.y} L${p3.x},${p3.y} Z`) // .attr("stroke", "#000") var hex = /^#[\da-f]{3}$|^#[\da-f]{6}$/i; if (fill !== undefined) { if (fill.match(hex)) { path.attr("fill", fill).attr("stroke", fill); } else { path.attr("fill", `url(#${fill})`) // .attr("stroke", `url(#${fill})`); } } return function() { return path.node(); }; }, /** * */ buildGradient: function(p1, p2, id, hex) { var fill = d3.select(document.createElementNS(d3.ns.prefix.svg, "linearGradient")) .attr("gradientUnits", "userSpaceOnUse") .attr("id", id) .attr("x1", p1.x) .attr("y1", p1.y) .attr("x2", p2.x) .attr("y2", p2.y) fill.append("stop") .attr("offset", "0%") .attr("stop-color", hex) fill.append("stop") .attr("offset", "100%") .attr("stop-color", "#fff") .attr("stop-opacity", "0") return function() { return fill.node(); }; }, }; /** * */ (function() { var svg = d3.select("body").append("svg") .attr("width", 500) .attr("height", 500); var defs = svg.append("defs"); var points = [ [ new Point(100, 0, '#f00'), new Point(200, 200, '#0f0'), new Point(0, 300, '#00f') ] // [ // new Point(100, 0, '#f00'), // new Point(200, 200, '#0f0'), // new Point(300, 0, '#00f') // ], // [ // new Point(300, 300, '#f00'), // new Point(200, 200, '#0f0'), // new Point(300, 0, '#00f') // ], ]; var subpathA; var subpathB; var subpathC; var subpathM1; var subpathM2; var subpathM3; for (var i = 0, len = points.length; i < len; i++) { var T = new Triangle(points[i][0], points[i][1], points[i][2]); subpathA = T.buildPath(T.subpathA[0], T.subpathA[1], T.subpathA[2], points[i][0].hex); subpathB = T.buildPath(T.subpathB[0], T.subpathB[1], T.subpathB[2], points[i][1].hex); subpathC = T.buildPath(T.subpathC[0], T.subpathC[1], T.subpathC[2], points[i][2].hex); defs.append(T.buildGradient(T.midpointACBC, T.midpointBC, `fill-${i}-0`, points[i][0].hex)); defs.append(T.buildGradient(T.midpointABBC, T.midpointAC, `fill-${i}-1`, points[i][1].hex)); defs.append(T.buildGradient(T.midpointABAC, T.midpointAB, `fill-${i}-2`, points[i][2].hex)); subpathM1 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-0`); subpathM2 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-1`); subpathM3 = T.buildPath(T.midpointAB, T.midpointAC, T.midpointBC, `fill-${i}-2`); svg.append(subpathA); svg.append(subpathB); svg.append(subpathC); svg.append(subpathM1); svg.append(subpathM2); svg.append(subpathM3); } }());