supercircles in JavaScript

Kragen Javier Sitaker kragen at pobox.com
Sat Mar 3 03:37:01 EST 2007


This will also be online at http://pobox.com/~kragen/sw/lame.html for
easier viewing.  Like everything else posted here without a notice
to the contrary, I dedicate this to the public domain.

<html><head><title>Curves of Lamé</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- about an hour of work, 2007-02-08 -->
<script type="text/javascript">//<![CDATA[
function $(id) { return document.getElementById(id) }
function drawCurve(ctx, points, x, y) {
  ctx.beginPath()
  ctx.moveTo(0, y)
  for (var ii = 0; ii < points.length; ii++) {
    ctx.lineTo(points[ii][0] * x, points[ii][1] * y)
  }
  ctx.stroke()
}

function redraw(canvas, exponent) {
  var ctx = canvas.getContext('2d')
  var w = canvas.width
  var h = canvas.height
  ctx.strokeStyle = 'grey'

  // set coordinate system
  ctx.save()
  ctx.translate(w/2, h/2)
  // the -1s are so that antialiased lines don't become half-width
  // when they reach the edge:
  ctx.scale(w/2-1, h/2-1)  
  ctx.lineWidth = 1/(w/2-1)

  // draw axes
  if ($('draw_axes').checked) {
    ctx.moveTo(-1, 0)
    ctx.lineTo(1, 0)
    ctx.moveTo(0, -1)
    ctx.lineTo(0, 1)
    ctx.stroke()
  }
  
  // compute a point per pixel
  var points = []
  for (var xx = 0; xx <= 1; xx += 1/(w/2-1)) {
    // x^n + y^n = 1; y = (1 - x^n)^(1/n)
    var yy = Math.pow(1 - Math.pow(xx, exponent), 1/exponent)
    points.push([xx, yy])
  }
  points.push([1, 0])  // ensure it's closed to take care of numerical error

  // draw them
  drawCurve(ctx, points, 1, 1)
  drawCurve(ctx, points, 1, -1)
  drawCurve(ctx, points, -1, 1)
  drawCurve(ctx, points, -1, -1)

  // restore coordinate system
  ctx.restore()
}
function cls(canvas) {
  canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height)
}
function draw() {
  var ss = $('exponent')
  redraw($('canvas'), ss.options[ss.selectedIndex].value)
}
function erase_old() {
  cls($('canvas'))
  draw()
}
// ]]>
</script>
</head>
<body onload="draw()">
<h1>Curves of Lamé</h1>
<div style="float:right; margin-left: 0.5em">
<div>
<label for="exponent">Exponent: 
</label><select onchange="draw()" id="exponent">
<option>0.125</option>
<option>0.25</option>
<option>0.368</option>
<option>0.5</option>
<option>0.707</option>
<option>1</option>
<option>1.414</option>
<option>2</option>
<option selected="selected">2.718</option>
<option>3</option>
<option>4</option>
<option>8</option>
<option>50</option>
<option>500</option>
<option>5000</option>
</select>
<button onclick="erase_old()">Erase Old</button>
<input type="checkbox" id="draw_axes" checked="checked" 
  onchange="erase_old()" /><label for="draw_axes"> Draw Axes</label>
</div>
<canvas id="canvas" width="400" height="400" style="margin: 0.5em">
</canvas>
</div>

<p>These are curves of Lamé, generalizations of the circle given by
the formula <nobr><i>x<sup>n</sup> + y<sup>n</sup></i> = 1</nobr>.
When <i>n</i> = 2, you get a circle; when <i>n</i> is a bit greater
than 2, you get Piet Hein’s “supercircles”.  He liked the effect you
got when <i>n</i> was roughly <i>e</i>, which is the default here, but
you can change the exponent in the drop-down box to see the different
kinds of curves you can get.</p>

</body></html>



More information about the Kragen-hacks mailing list