Skip to content

Instantly share code, notes, and snippets.

@GabrielJones646
Last active November 22, 2016 17:46
Show Gist options
  • Save GabrielJones646/5dd062ed369a354a3c33 to your computer and use it in GitHub Desktop.
Save GabrielJones646/5dd062ed369a354a3c33 to your computer and use it in GitHub Desktop.
// © 2015 Gabriel Jones
case class ComplexNumber(r: Double, i: Double){
def +(that: ComplexNumber) = ComplexNumber(r + that.r, i + that.i)
def -(that: ComplexNumber) = ComplexNumber(r - that.r, i - that.i)
def *(that: ComplexNumber) = ComplexNumber(r*that.r - i*that.i, r*that.i + i*that.r)
def mag() = r*r + i*i
}
object ScalaJSExample extends js.JSApp{
def main(): Unit = {
val TAU = 2*Math.PI
val LIMIT = 255
// val (xCenter, yCenter) = (3.5/2 - 2.5, 3.5/2 - 1.75)
// val width = 3.5
val (xCenter, yCenter) = (-0.55, 0.6)
val width = 0.1
val (xMin, xMax) = (xCenter - width/2, xCenter + width/2)
val (yMin, yMax) = (yCenter - width/2, yCenter + width/2)
val (rasterHeight, rasterWidth) = (512, 512)
def cAt(px: Int, py: Int) = {
val x = xMin + (xMax - xMin) / rasterWidth * px
val y = yMin + (yMax - yMin) / rasterHeight * (rasterHeight-py)
ComplexNumber(x,y)
}
def iterations(c: ComplexNumber) = {
lazy val zn: Stream[ComplexNumber] = c #:: zn.map{zp => zp * zp + c}
zn.take(LIMIT).takeWhile(_.mag < 4).length
}
def hue(iters: Int) = iters % 360
for {
i <- 0 until 256
h = hue(i)
} {
Page.renderer.fillStyle = s"hsl($h,100%,50%)"
Page.renderer.fillRect(i, 0, 1, 1)
}
val palette = Page.renderer.getImageData(0, 0, 256, 1).data
val raster = Array.ofDim[Byte](rasterWidth, rasterHeight)
lazy val fs: Stream[Int] = 2 #:: fs.map(_ *2)
val drawPixels = (for {
f <- fs.toIterator.take(9)
pRadius = 512.0 / f * 1.5
_ = dom.console.log(s"$f, $pRadius")
pixelY <- ((512 / f) until rasterHeight by (512 / (f / 2))).toIterator
pixelX <- ((512 / f) until rasterWidth by (512 / (f / 2))).toIterator
iters = iterations(cAt(pixelX, pixelY))
h = hue(iters)
fillStyle = {
val grd = Page.renderer.createRadialGradient(pixelX, pixelY, 1, pixelX, pixelY, pRadius)
grd.addColorStop(0,if (iters >= LIMIT) "rgba(0,0,0,1.0)" else s"hsla($h,100%,50%,1.0)")
grd.addColorStop(1,if (iters >= LIMIT) "rgba(0,0,0,0.0)" else s"hsla($h,100%,50%,0.0)")
grd
}
d: Unit = {
Page.renderer.fillStyle = fillStyle
Page.renderer.beginPath()
Page.renderer.arc(pixelX, pixelY, pRadius, 0.0, TAU)
Page.renderer.fill()
raster(pixelX)(pixelY) = iters.toByte
}
} yield d) ++
( for {
(offsetX, offsetY) <- Seq((0,0), (1,0), (0,1)).toIterator
pRadius = 1.0
_ = dom.console.log(s"$offsetX,$offsetY, $pRadius")
pixelY <- (offsetX until rasterHeight by 2).toIterator
pixelX <- (offsetY until rasterWidth by 2).toIterator
iters = iterations(cAt(pixelX, pixelY))
h = hue(iters)
fillStyle = if (iters >= LIMIT) "rgb(0,0,0)" else s"hsl($h,100%,50%)"
d: Unit = {
Page.renderer.fillStyle = fillStyle
Page.renderer.fillRect(pixelX, pixelY, 1, 1)
raster(pixelX)(pixelY) = iters.toByte
}
} yield d)
var cycleCount = 255 * 100
def cyclePalette = dom.setInterval(()=>{
val id = Page.renderer.getImageData(0, 0, rasterWidth, rasterHeight)
val idd = id.data
for {
py <- 0 until rasterHeight
px <- 0 until rasterWidth
if raster(px)(py) > 0
nCi = (raster(px)(py) + cycleCount) % 255
rgbi <- 0 until 3
} {
idd((px + py * rasterWidth) * 4 + rgbi) = palette(nCi * 4 + rgbi)
}
Page.renderer.putImageData(id, 0, 0)
cycleCount -= 1
}, 0)
def asynchronousIteration: Unit = {
var start = js.Date.now()
while (js.Date.now() - 50 < start && drawPixels.hasNext) drawPixels.next
if (drawPixels.hasNext) dom.setTimeout(asynchronousIteration _, 0) else {
println("done")
cyclePalette
}
}
asynchronousIteration
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment