|
<!DOCTYPE html> |
|
<svg width="960" height="500"> |
|
<g id='sandbox' transform='translate('+[960/2, 500/2]+')'> |
|
</g> |
|
</svg> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
const maxLayers=1000; |
|
const svg = d3.select('#sandbox'); |
|
|
|
const primes=[2, 3]; |
|
function isPrime(number) { |
|
if (number<4) return true; |
|
const limit = Math.sqrt(number); |
|
for(var primeIdx=0; primeIdx<primes.length && primes[primeIdx]<=limit; primeIdx++) { |
|
const prime=primes[primeIdx]; |
|
if (number%prime==0) { |
|
return false; |
|
} |
|
} |
|
primes.push(number); |
|
return true; |
|
} |
|
|
|
function yPos(cnt,layer, total) { |
|
//there is a axial symetry. Let's start in a corner |
|
const halfCount=total/2; //we are sure it is an even number |
|
const half = (Math.floor(cnt/halfCount)%2==0)?1:-1; |
|
//the y pos is limited to layer*2+1 |
|
const y=Math.min(layer*2, cnt%halfCount); |
|
return half*(y-layer); |
|
} |
|
function xPos(cnt,layer, total) { |
|
//the position is the same with a phase of a quarter |
|
return yPos(cnt+total/4, layer, total); |
|
} |
|
|
|
|
|
svg.append('circle').attr('r', 3) |
|
.attr('fill', 'red') |
|
.attr('cx', 0) |
|
.attr('cy', 0); |
|
|
|
const zoom=1; |
|
const layer = d3.range(maxLayers); //layer is the level from the center |
|
let current=1; |
|
|
|
layer.map(l=>{ |
|
const totalPointCount = l*8; |
|
const count=d3.range(totalPointCount); // count of points per layer |
|
for (let c=0;c<totalPointCount; c++) { |
|
if (isPrime(current++)) { |
|
svg.append('circle').attr('r', 1) |
|
.attr('cx', zoom*xPos(c, l, totalPointCount)) |
|
.attr('cy', zoom*yPos(c, l, totalPointCount)); |
|
} |
|
}; |
|
}); |
|
console.log("displayed primes="+primes.length) |
|
|
|
</script> |