'use strict'; /** * */ function Mesh() { // // Color seed coordinants // this.seeds = []; // Length of a side this.side = 10; // // How far a seed will extend its reach this.seedWeight = 40; // this.width = 400; this.height = 400; var faces = this.initFaces(this.width, this.height, this.side); this.addSeed(new Seed(0, 0, '#ff0000', this.seedWeight), faces); this.addSeed(new Seed(0, 39, '#0000ff', this.seedWeight), faces); this.addSeed(new Seed(39, 0, '#00ff00', this.seedWeight), faces); this.addSeed(new Seed(39, 39, '#ffff00', this.seedWeight), faces); this.calculateFills(faces); var svg = d3.select("body").append("svg").attr('width', this.width).attr('height', this.height); svg.selectAll('rect') .data(faces) .enter() .append('rect') .attr('id', function(d) { return d.id; }) .attr('x', function(d) { return d.x; }) .attr('y', function(d) { return d.y; }) .attr('width', function(d) { return d.side; }) .attr('height', function(d) { return d.side; }) .attr('fill', function(d) { return d.fill; }) .attr('stroke', 0) // d3.select(id).attr('fill', seed.fill); // for (var i = 0, len = seeds.length; i < len; i++) { // d3.select(seeds[i].faceId).attr('fill', seeds[i].fill); // } }; /** * */ function Face(id, x, y, side) { this.id = id; this.x = x; this.y = y; this.side = side; this.fill = '#fff'; this.colors = []; }; /** * */ function Seed(x, y, fill, weight) { this.x = x; this.y = y; this.fill = fill; this.weight = weight; }; /** * */ Mesh.prototype = { /** * Faces must be a one dimensional array to pass to D3. */ initFaces: function(width, height, side) { var countW = Math.ceil(width / side); var countH = Math.ceil(height / side); var all = []; for (var w = 0; w < countW; w++) { for (var h = 0; h < countH; h++) { all.push(new Face( `f-${w}-${h}-${all.length}`, w * side, h * side, side )); } } return all; }, /** * */ calculateFills: function(faces) { var len = faces.length; var hexes; var populate = function(color) { var arr = []; for (var k = 0; k < color.weight; k++) { arr.push(color.hex); } return arr; }; for (var i = 0; i < len; i++) { var hexes = []; for (var j = 0; j < faces[i].colors.length; j++) { hexes = hexes.concat(populate(faces[i].colors[j])); } while (hexes.length < this.seedWeight) { hexes.push('#ccccff'); } faces[i].fill = Compositor.averageHexCollection(hexes); } }, /** * */ addSeed: function(seed, faces) { var n = this.seedWeight; var len = faces.length; var delta, index, weight; var countX = this.width / this.side; var countY = this.height / this.side; for (var x = (seed.x - n + 1); x < seed.x + n; x++) { if (x < 0 || x >= countX) { continue; } for (var y = (seed.y - n + 1); y < seed.y + n; y++) { if (y < 0 || y >= countY) { continue; } // Diamond shapes around source drop weighting incrementally. delta = Math.abs(seed.x - x) + Math.abs(seed.y - y); weight = Math.max(0, n - delta); index = x * countY + y; if (weight > 0 && index >= 0 && index < len) { faces[index].colors.push({ hex: seed.fill, weight: weight }); } } } }, }; /** * */ var Compositor = { /** * */ averageComponentCollection: function(collection) { var len = collection.length; var total = 0; for (var i = 0; i < len; i++) { total += parseInt(collection[i], 16); } var avg = Math.round(total / len); avg = avg.toString(16); avg = ('00' + avg).slice(-2); return avg; }, /** * */ averageHexCollection: function(collection) { // check hex against regex var allR = []; var allG = []; var allB = []; var len = collection.length; var tmp, hex; for (var i = 0; i < len; i++) { tmp = collection[i].substr(1); allR.push(tmp.substr(0, 2)); allG.push(tmp.substr(2, 2)); allB.push(tmp.substr(4, 2)); } var r = this.averageComponentCollection(allR); var g = this.averageComponentCollection(allG); var b = this.averageComponentCollection(allB); return '#' + r + g + b; }, }; var mesh = new Mesh();