d3 / d3-shape

Graphical primitives for visualization, such as lines and areas.
https://d3js.org/d3-shape
ISC License
2.47k stars 305 forks source link

What have you got against the Super Ellipse ? #129

Closed Carelvd closed 4 years ago

Carelvd commented 5 years ago

Hi,

I was looking at the shapes library and noticed you were missing super ellipses, after a cry I figured I might supply you with some script to generate them but my JavaScript is rubbish so this submission might make you cry a little too. The attached superEllipse.txt should be renamed to superEllipse.js and slapped into the d3/shapes library alongside the circles.js and squares.js (Perhaps consider renaming the file to squircles ? IDK).

I have made the script render 21 points for the shape but you may require higher/lower fidelity. The following Python script will allow you to generate further scripts with higher/lower fidelity. To use the script substitute P in the first line with the required number of points.

    t = (P)*4+1
    print("export var superEllipse = {")
    print(" draw : function (context, size) {}")
    print("  var W = size;")
    print("  var H = size;")
    print("  var w = W/2;")
    print("  var h = H/2;")
    print("  var n = 2/4;")
    for i in range(t) :
        if i:
         print(f"  context.lineTo(W/2*Math.sign(Math.cos({i:2}/{t}*2*Math.PI))*Math.pow(Math.abs(Math.cos({i:2}/{t}*2*Math.PI)), n), H/2*Math.sign(Math.sin({i:2}/{t}*2*Math.PI))*Math.pow(Math.abs(Math.sin({i:2}/{t}*2*Math.PI)), n));")
        else :
         print(f"  context.moveTo(W/2*Math.sign(Math.cos({i:2}/{t}*2*Math.PI))*Math.pow(Math.abs(Math.cos({i:2}/{t}*2*Math.PI)), n), H/2*Math.sign(Math.sin({i:2}/{t}*2*Math.PI))*Math.pow(Math.abs(Math.sin({i:2}/{t}*2*Math.PI)), n));")
    print("  contest.closePath();")
    print("  }")
    print("};"

It turns out that most of the detail is in the corners and that the top/bottom/left/right edges are more for making the shape look plumper then a rectangle. The P^{th} point may be thought of as an edge point, while the remaining P-1 points are used to provide detail in the corners, Using a P of 4 seems to give a nice enough shape, that is one for each edge and three points in the corners as below.

image

Otherwise you may know of some bezier curve trickery that might generate the visual result.

Sorry this ain't a formal PR but it was quicker to merely attach a script.

Updated : I had included a half width/height offset which in retrospect was incorrect.

superellipse.txt

mbostock commented 4 years ago

Here are some implementations:

https://bl.ocks.org/mbostock/1021103 https://observablehq.com/@toja/superellipse https://github.com/d3/d3-plugins/blob/master/superformula/superformula.js