// Mike Bostock’s Block http://bl.ocks.org/mbostock/1021103 // Christophe Viau implemented a new shape type as a D3 plugin based on superformulas. (function() { d3.superformula = function superformula() { var _symbol = d3.symbol(), _line = d3.line(); function d3_functor(v) { return typeof v === "function" ? v : function() { return v; }; } function transform(_) { if (!_) return noop; var x0 = 0, y0 = 0, kx = 1, ky = 1, dx = _.tx, dy = _.ty, rot = _.rot // rads var transform = function(p = [1, 1]) { var point = [] x0 = (x0 === undefined) ? x0 : 0 y0 = (y0 === undefined) ? y0 : 0 var pointx = p[0] * Math.cos(rot) - p[1] * Math.sin(rot) var pointy = p[0] * Math.sin(rot) + p[1] * Math.cos(rot) point[0] = (x0 += pointx) * kx + dx point[1] = (y0 += pointy) * ky + dy return point } return transform } function transformPath(params, path) { var _transform = transform(params) let tpath = [] for (let i = 0; i < path.length; i++) { tpath.push(_transform(path[i])) } return tpath } var formdefinition = {m: 12, n1: .3, n2: 0, n3: 10, a: 1, b: 1, tx: 0, ty: 0, rot: 0, rad: 100, segs: 100} var type = null var size = _symbol.size() // size of the extent var segs = _symbol.size() // number of segments of resulting path var formparams = {} // passed superformula and transform formparams var points = [] // transformed path points var extent = [] // transformed suprescribing square var tcenter = [] // transformed center transform[0, 0] var defparams = {} // form definition params function _superformulaPath(points) { return _line(points) + "Z"; // return path } function _superformulaPoints(params) { var pta = Math.max(params.pta || 0 , 0) var ptb = Math.min(params.ptb || params.segs + 1, params.segs + 1) var n = params.segs var i = -1, dt = 2 * Math.PI / n, // sector per symmetry dimension t, r = 0, // initialize x, y, pts = []; // points in path // while (++i < n) { i = pta-1; while (++i < ptb - 1) { t = params.m * (i * dt - Math.PI) / 4; t = Math.pow(Math.abs(Math.pow(Math.abs(Math.cos(t) / params.a), params.n2) + Math.pow(Math.abs(Math.sin(t) / params.b), params.n3)), -1 / params.n1); if (t > r) r = t; pts.push(t); } let rad = params.rad r = rad / r // * Math.SQRT1_2 / r // normalize _e_ tbc // i = -1; while (++i < n) { i = -1; while (++i < ptb - pta - 1) { let pt = [(t = pts[i] * r) * Math.cos(i * dt), t * Math.sin(i * dt)] pts[i] = [Math.abs(pt[0]) < 1e-6 ? 0 : pt[0], Math.abs(pt[1]) < 1e-6 ? 0 : pt[1]] } return pts; } function superformula(d, i) { var n var p = formdefinition // initialize form params for (n in formparams) p[n] = formparams[n].call(this, d, i) if (d && d.shapeParams !== 'undefined') { for (n in d.shapeParams) p[n] = d3_functor(d.shapeParams[n]).call(this, d, i) } var rpoints = _superformulaPoints(p) points = transformPath(p, rpoints) // assign for points getter return _superformulaPath(points) } superformula.type = function(x) { if (!arguments.length) return type; type = d3_functor(x); return superformula; }; superformula.formParam = function(name, value) { if (arguments.length < 2) return formparams[name]; formparams[name] = d3_functor(value); return superformula; }; superformula.formparams = function(p) { if (arguments.length < 1) { let n, p = {} for (n in formparams) p[n] = formparams[n]() return p } for (let n in p) { formparams[n] = (typeof (p[n]) === "function") ? p[n] : d3_functor(p[n]) } return superformula; } // defparams superformula.defparams = function() { if (!arguments.length) return defparams; } superformula.types = function(x) { if (!arguments.length) return types types = x return superformula }; // size of superformula in square pixels superformula.size = function(x) { if (!arguments.length) return size() size = d3_functor(x); return superformula; }; // number of discrete line segments superformula.segs = function(x) { if (!arguments.length) return segs() segs = d3_functor(x); return superformula; }; superformula.points = function() { if (!arguments.length) return points } superformula.point = function(p) { if (arguments.length == 1) return points[p] } return superformula; } })();