zoomIn & zoomOut: http://bl.ocks.org/linssen/7352810 //---------------------------------------------------------------------------------------------------- // MARKERS & STICKY NODES //---------------------------------------------------------------------------------------------------- http://jsfiddle.net/7HZcR/3/ http://jsfiddle.net/thatOneGuy/7HZcR/502/ function tick() { path.attr('d', function(d) { var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = 75 / d.linknum; return 'M' + d.source.x + ',' + d.source.y + 'A' + dr + ',' + dr + ' 0 0,1 ' + d.target.x + ',' + d.target.y; }); } // Per-type markers, as they don't inherit styles. svg.append('svg:defs') .selectAll('marker') .data(['suit', 'licensing', 'resolved']) .enter().append('svg:marker') .attr('id', String) .attr('viewBox', '0 -5 10 10') .attr('refX', 15) .attr('refY', -1.5) .attr('markerWidth', 6) .attr('markerHeight', 6) .attr('orient', 'auto') .append('svg:path') .attr('d', 'M0,-5L10,0L0,5'); .attr('marker-end', function(d) { return 'url(#' + d.type + ')'; }); function fixedNodes() { circle.each(function(d) { d.fixed = true; }); } path.attr('d', function(d) { var curve = 2; var homogeneous = 3.2; var dx = d.target.x - d.source.x, dy = d.target.y - d.source.y, dr = Math.sqrt(dx * dx + dy * dy) * (d.linknum + homogeneous) / (curve * homogeneous); return 'M' + d.source.x + ',' + d.source.y + 'A' + dr + ',' + dr + ' 0 0,1 ' + d.target.x + ',' + d.target.y; }); //---------------------------------------------------------------------------------------------------- // REGULAR POLYGON SHAPES //---------------------------------------------------------------------------------------------------- // SVG regular poligons: http://codepen.io/thebabydino/pen/WbjdRq function setAttrs(attr_obj) { for (var prop in attr_obj) { this.setAttribute(prop, attr_obj[prop]); } } var NS_URI = 'http://www.w3.org/2000/svg'; // What do the p and q mean? p is the number of vertices. They are all distributed evenly on a circle. For q =1, you connect each point to the next one on the circle (clockwise or counterclockwise, it doesn't matter). For q = 2, you skip the first one and connect to the 2nd. For q = 3, you skip the first two and connect to the 3rd. And so on... as long as q < p/2. var generatePoly = function(parent, p, q, r) { var path = document.createElementNS(NS_URI, 'path'), points = document.createElementNS(NS_URI, 'g'), curr_g, curr_point, base_angle = 2 * Math.PI / p, angle = (Math.random() - q) * base_angle, x, y, d_attr = ''; for (var i = 0; i < p; i++) { curr_g = document.createElementNS(NS_URI, 'g'); angle += q * base_angle; x = ~~(r * Math.cos(angle)); y = ~~(r * Math.sin(angle)); d_attr += ((i === 0) ? 'M' : 'L') + x + ' ' + y + ' '; if (i * q % p === 0 && i > 0) { angle += base_angle; x = ~~(r * Math.cos(angle)); y = ~~(r * Math.sin(angle)); d_attr += 'M' + x + ' ' + y + ' '; } curr_point = document.createElementNS(NS_URI, 'circle'); setAttrs.call(curr_point, { 'class': 'p p--' + i, 'cx': x, 'cy': y, 'r': 32 }); curr_g.appendChild(curr_point); points.appendChild(curr_g); } d_attr += 'z'; path.setAttribute('d', d_attr); path.setAttribute('fill-rule', 'evenodd'); parent.appendChild(path); parent.appendChild(points) };