block by syntagmatic 5070320

Ulam Spirals

Full Screen

index.html

<meta charset="utf-8">
<title>Ulam Spirals</title>
<style>
  html, body {
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    background: #000;
    color: #eee;
    font: 11px 'Lucida Grande', sans-serif;
  }
  a, a:visited {
    color: #62d7ff;
    text-decoration: none;
  }
  footer {
    color: #fff;
    position: absolute;
    bottom: 0;
    right: 15;
    text-align: center;
    font-size: 12px;
    padding: 4px;
    background: rgba(0,0,0,0.5);
  }
</style>
<body>
<canvas id="canvas" width=960 height=500></canvas>
<footer>Ulam Spirals, adapted from <a href="//www.bigblueboo.com/prime/">Prime Explorer</a></footer>
</body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="dat.gui.js"></script>
<script>
window.onload = function() {
  var canvas = document.getElementById("canvas");
  var width = canvas.width = document.body.clientWidth || 960,
      height = canvas.height = document.body.clientHeight || 500,
      size = 2,
      ulamN = 4,
      max = 6e5,
      start = 1,
      numcols = Math.floor(width / size),
      numrows = Math.floor(height / size),
      colors = ["#ffc344", "#000000"];

  var ctx = canvas.getContext("2d");
  ctx.save();

  var latest = 0;
  function plotUlam(n) {
    // rerender invalidation
    var current = ++latest;

    // reset canvas
    ctx.restore();
    ctx.save();

    ctx.fillStyle = colors[0];
    ctx.clearRect(0,0,width,height);
    ctx.translate(width/2,height/2);

    var maxRunLength = 1;
    var runLength = 1;
    var runCount = n - 2;
    var integer = 0;

    function step() {
      integer++;
      
      // our work is complete
      if (integer > max) return false;

      // our work was interrupted
      if (latest > current) return false;

      // transform the geometry
      ctx.translate(size,0);
      runLength--;
      if (runLength < 1) {
        runCount--;
        if (runCount < 1) {
          runCount = n - 2;
          maxRunLength++;
        }
        runLength = maxRunLength;
        ctx.rotate(Math.PI * 2 / n);
      }

      // perform tests on the integer
      var prime = isPrime(integer + start - 1);

      // render primes differently
      if (!prime) return;
      //ctx.fillStyle = prime ? colors[0] : colors[1];

      // render the integer
      ctx.fillRect(-size/2, -size/2, size, size);
    };

    d3.timer(function() {
      var ii = 10000;         // number of integers to render at once 
      var done = false;
      while (ii-- > 0) {
        step() ? false : done = true
      }
      return !done; // if done is true, stop rendering
    }); 
  }

  /* Primality Testing */
  // //www.javascripter.net/faq/numberisprime.htm

  function leastFactor(n){
    if (isNaN(n) || !isFinite(n)) return NaN;  
    if (n==0) return 0;  
    if (n%1 || n*n<2) return 1;
    if (n%2==0) return 2;  
    if (n%3==0) return 3;  
    if (n%5==0) return 5;  
    var m = Math.sqrt(n);
    for (var i=7;i<=m;i+=30) {
     if (n%i==0)      return i;
     if (n%(i+4)==0)  return i+4;
     if (n%(i+6)==0)  return i+6;
     if (n%(i+10)==0) return i+10;
     if (n%(i+12)==0) return i+12;
     if (n%(i+16)==0) return i+16;
     if (n%(i+22)==0) return i+22;
     if (n%(i+24)==0) return i+24;
    }
    return n;
  }

  function isPrime (n) {
    if (isNaN(n) || !isFinite(n) || n%1 || n<2) return false; 
    if (n==leastFactor(n)) return true;
    return false;
  }

  /* Plot some primes */
  plotUlam(ulamN);

  /* Interactive Parameters with Dat.Gui*/

  var Gui = function() {
    this.ulam = ulamN;
    this.size = size;
    this.max = max;
    this.start = start;
    this.color1 = colors[0];
    this.color2 = colors[1];
  };

  var field = new Gui();
  var gui = new dat.GUI();
  var ulam = gui.add(field, 'ulam', 3, 10).step(1);
  var sizer = gui.add(field, 'size', 0.5, 6).step(0.5);
  var maxer = gui.add(field, 'max', 500, 1e7).step(500);
  var starter = gui.add(field, 'start', 1, 1e8).step(1);
  var color1 = gui.addColor(field, 'color1');
  var color2 = gui.addColor(field, 'color2');

  ulam.onChange(function(v) { ulamN = v; plotUlam(ulamN); });
  sizer.onChange(function(v) { size = v; plotUlam(ulamN); });
  maxer.onChange(function(v) { max = v; plotUlam(ulamN); });
  starter.onChange(function(v) { start = v; plotUlam(ulamN); });
  color1.onChange(function(v) { colors[0] = v; plotUlam(ulamN); });
  color2.onChange(function(v) { colors[1] = v; d3.select("body").style("background", colors[1]); });
};

</script>