diff --git a/dist/index.html b/dist/index.html index 2efed2a..3573f06 100644 --- a/dist/index.html +++ b/dist/index.html @@ -2,6 +2,15 @@ Queer Mandelbrot + diff --git a/src/canvas.mjs b/src/canvas.mjs index 9d7af0c..3659b7b 100644 --- a/src/canvas.mjs +++ b/src/canvas.mjs @@ -2,7 +2,36 @@ export const getContext = (id) => document.getElementById(id).getContext("2d"); +export const getInnerWidth = () => + window.innerWidth; + +export const getInnerHeight = () => + window.innerHeight; + +export const onResize = (callback) => + window.addEventListener("resize", callback); + export const setPixel = (ctx, x, y, color) => { ctx.fillStyle = color; ctx.fillRect(x, y, 1, 1); }; + +export const clear = (ctx) => { + ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); +}; + +export const setSize = (ctx, width, height) => { + ctx.canvas.width = width; + ctx.canvas.height = height; +}; + +export const requestAnimationFrame = (callback) => { + let eventListener = () => { + callback(); + window.removeEventListener("message", eventListener); + } + + window.addEventListener("message", eventListener) + window.postMessage(null); +}; +//window.requestAnimationFrame; diff --git a/src/queermandelbrot.gleam b/src/queermandelbrot.gleam index 650a646..58a4362 100644 --- a/src/queermandelbrot.gleam +++ b/src/queermandelbrot.gleam @@ -70,41 +70,81 @@ fn value_to_color(colorscheme: ColorScheme, value: Int) -> String { } } -pub fn main() { +fn animate_for_each( + list: List(a), + still_valid: fn() -> Bool, + callback: fn(a) -> Nil, +) -> Nil { + case list, still_valid() { + _, False -> Nil + [], True -> Nil + [head, ..rest], True -> { + callback(head) + request_animation_frame(fn() { + animate_for_each(rest, still_valid, callback) + }) + } + } +} + +fn redraw(ctx: Context2D, canvas_width: Int, canvas_height: Int) { let colorscheme = Lesbian - let ctx = get_context("mandelbrot") + set_size(ctx, canvas_width, canvas_height) + clear(ctx) - let canvas_width = 600 - let canvas_height = 400 let min_x = -2.0 let max_x = 1.0 let min_y = -1.0 let max_y = 1.0 list.range(0, canvas_width - 1) - |> list.each(fn(x) { - list.range(0, canvas_height - 1) - |> list.each(fn(y) { - let location = - Complex( - real: int.to_float(x) - /. int.to_float(canvas_width) - *. { max_x -. min_x } - +. min_x, - imaginary: int.to_float(y) - /. int.to_float(canvas_height) - *. { max_y -. min_y } - +. min_y, - ) - let value = get_mandelbrot_value(location, 1000.0, Complex(0.0, 0.0), 0) - case value { - Converges -> set_pixel(ctx, x, y, "#000") - Diverges(value) -> - set_pixel(ctx, x, y, value_to_color(colorscheme, value)) - } - }) - }) + |> list.sized_chunk(1) + |> animate_for_each( + fn() { + get_inner_width() == canvas_width && get_inner_height() == canvas_height + }, + list.each(_, fn(x) { + io.debug(x) + list.range(0, canvas_height - 1) + |> list.each(fn(y) { + let pad_horizontal = + { max_x -. min_x } /. { max_y -. min_y } + <. int.to_float(canvas_width) /. int.to_float(canvas_height) + + let #(sizing_factor, x_offset, y_offset) = case pad_horizontal { + True -> #(canvas_height, min_x, min_y) + False -> #(canvas_width, min_x, min_y) + } + + let location = + Complex( + real: int.to_float(x) + /. int.to_float(sizing_factor) + *. { max_x -. min_x } + +. x_offset, + imaginary: int.to_float(y) + /. int.to_float(sizing_factor) + *. { max_y -. min_y } + +. y_offset, + ) + let value = get_mandelbrot_value(location, 1000.0, Complex(0.0, 0.0), 0) + case value { + Converges -> set_pixel(ctx, x, y, "#000") + Diverges(value) -> + set_pixel(ctx, x, y, value_to_color(colorscheme, value)) + } + }) + }), + ) +} + +pub fn main() { + let ctx = get_context("mandelbrot") + + redraw(ctx, get_inner_width(), get_inner_height()) + + on_resize(fn() { redraw(ctx, get_inner_width(), get_inner_height()) }) } type Context2D @@ -112,5 +152,23 @@ type Context2D @external(javascript, "./canvas.mjs", "getContext") fn get_context(id: String) -> Context2D +@external(javascript, "./canvas.mjs", "getInnerWidth") +fn get_inner_width() -> Int + +@external(javascript, "./canvas.mjs", "getInnerHeight") +fn get_inner_height() -> Int + +@external(javascript, "./canvas.mjs", "onResize") +fn on_resize(callback: fn() -> Nil) -> Nil + @external(javascript, "./canvas.mjs", "setPixel") fn set_pixel(ctx: Context2D, x: Int, y: Int, color: String) -> Nil + +@external(javascript, "./canvas.mjs", "clear") +fn clear(ctx: Context2D) -> Nil + +@external(javascript, "./canvas.mjs", "setSize") +fn set_size(ctx: Context2D, width: Int, height: Int) -> Nil + +@external(javascript, "./canvas.mjs", "requestAnimationFrame") +fn request_animation_frame(callback: fn() -> Nil) -> Nil