diff --git a/webfront/lib.rs b/webfront/lib.rs index 867de1d..08bf3f9 100644 --- a/webfront/lib.rs +++ b/webfront/lib.rs @@ -135,24 +135,26 @@ pub struct ShallowWaterUniverse(shallow_water::System); impl ShallowWaterUniverse { #[wasm_bindgen(constructor)] pub fn new(height: usize, width: usize) -> Self { - let x = (0.0, 1.0, width); - let y = (0.0, 1.0, height); + let x = (-0.5, 0.5, width); + let y = (-0.5, 0.5, height); Self(shallow_water::System::new(x, y)) } pub fn init(&mut self, x0: f32, y0: f32) { let nx = self.0.nx(); let ny = self.0.ny(); - let x = ndarray::Array1::linspace(0.0, 1.0, nx); - let y = ndarray::Array1::linspace(0.0, 1.0, ny); + let x = ndarray::Array1::linspace(-0.5, 0.5, nx); + let y = ndarray::Array1::linspace(-0.5, 0.5, ny); let (mut eta, mut etau, mut etav) = self.0.components_mut(); let sigma = 0.1; for j in 0..ny { + let y = y[j]; for i in 0..nx { - let r = f32::hypot(x[i] - x0, y[j] - y0); + let x = x[i]; + let r = f32::hypot(x - x0, y - y0); let f = 1.0 / (sigma * (2.0 * sbp::consts::PI).sqrt()) * f32::exp(-0.5 * (r / sigma).powi(2)); diff --git a/webfront/misc/index.html b/webfront/misc/index.html deleted file mode 100644 index 77c656e..0000000 --- a/webfront/misc/index.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - ΣBP Solver - - - - -
- -
- -
- - - -
- - diff --git a/webfront/misc/main.js b/webfront/misc/main.js deleted file mode 100644 index a0bb71d..0000000 --- a/webfront/misc/main.js +++ /dev/null @@ -1,301 +0,0 @@ -import { default as init, set_panic_hook as setPanicHook, - MaxwellUniverse, EulerUniverse, ShallowWaterUniverse } from "./sbp_web.js"; - -function compile_and_link(ctx, vsource, fsource) { - const program = ctx.createProgram(); - const vsShader = ctx.createShader(ctx.VERTEX_SHADER); - ctx.shaderSource(vsShader, vsource); - const fsShader = ctx.createShader(ctx.FRAGMENT_SHADER); - ctx.shaderSource(fsShader, fsource); - - ctx.compileShader(vsShader); - ctx.compileShader(fsShader); - ctx.attachShader(program, vsShader); - ctx.attachShader(program, fsShader); - ctx.linkProgram(program); - ctx.validateProgram(program); - - if (!ctx.getProgramParameter(program, ctx.LINK_STATUS)) { - console.error(`Linking of lineProgram failed: ${ctx.getProgramInfoLog(program)}`); - console.error(`vertex shader infolog: ${ctx.getShaderInfoLog(vsShader)}`); - console.error(`fragment shader infolog: ${ctx.getShaderInfoLog(fsShader)}`); - return null; - } - - ctx.deleteShader(vsShader); - ctx.deleteShader(fsShader); - - return program; -} - -class LineDrawer { - constructor(ctx) { - function lineProgram(ctx) { - const LINE_VERTEX_SHADER = String.raw` - #version 100 - attribute mediump float aX; - attribute mediump float aY; - - uniform vec4 uBbox; - - void main() { - mediump float x = (aX - uBbox.x)*uBbox.y; - mediump float y = (aY - uBbox.z)*uBbox.w; - gl_Position = vec4(2.0*x - 1.0, 2.0*y - 1.0, 1.0, 1.0); - } - - `; - const LINE_FRAGMENT_SHADER = String.raw` - #version 100 - - void main() { - gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); - } - `; - const program = compile_and_link(ctx, LINE_VERTEX_SHADER, LINE_FRAGMENT_SHADER); - - const uBbox = ctx.getUniformLocation(program, "uBbox"); - - return {inner: program, uniforms: {"uBbox": uBbox}}; - }; - this.program = lineProgram(ctx); - this.ctx = ctx; - } - set_xy(width, height, xBuffer, yBuffer, bbox) { - const ctx = this.ctx; - ctx.useProgram(this.program.inner); - { - let loc = ctx.getAttribLocation(this.program.inner, "aX"); - ctx.bindBuffer(ctx.ARRAY_BUFFER, xBuffer); - ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); - ctx.enableVertexAttribArray(loc); - - loc = ctx.getAttribLocation(this.program.inner, "aY"); - ctx.bindBuffer(ctx.ARRAY_BUFFER, yBuffer); - ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); - ctx.enableVertexAttribArray(loc); - } - const lineIdxBuffer = new Uint16Array(2*width*height - 1); - { - let n = 0; - for (let j = 0; j < height; j++) { - for (let i = 0; i < width; i++) { - if (j % 2 == 0) { - lineIdxBuffer[n] = width*j + i; - } else { - lineIdxBuffer[n] = width*(j + 1) - i - 1; - } - n += 1; - } - } - let m = lineIdxBuffer[n-1]; - let updown = "down"; - let lr; - if (height % 2 === 0) { - lr = "left"; - } else { - lr = "right"; - } - for (let i = 0; i < width; i++) { - for (let j = 0; j < height-1; j++) { - if (updown === "up") { - m += width; - } else { - m -= width; - } - lineIdxBuffer[n] = m; - n += 1; - } - if (n === 2*width*height - 1) { - continue; - } - if (lr === "left") { - m += 1; - } else { - m -= 1; - } - lineIdxBuffer[n] = m; - n += 1; - - if (updown === "down") { - updown = "up"; - } else { - updown = "down"; - } - } - } - this.indexBuffer = ctx.createBuffer(); - ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, lineIdxBuffer, ctx.STATIC_DRAW); - - ctx.uniform4f(this.program.uniforms.uBbox, bbox[0], 1.0/(bbox[1] - bbox[0]), bbox[2], 1.0/(bbox[3] - bbox[2])); - this.width = width; - this.height = height; - } - draw() { - const ctx = this.ctx; - ctx.useProgram(this.program.inner); - ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); - - ctx.drawElements(ctx.LINE_STRIP, 2*this.width*this.height - 1, ctx.UNSIGNED_SHORT, 0); - } -} - -(async function run() { - const eq_sel = document.getElementById("eq-set"); - display_eqset(eq_sel.value); - - const wasm = await init("./sbp_web_bg.wasm"); - setPanicHook(); - const canvas = document.getElementById("glCanvas"); - - const gl = canvas.getContext("webgl"); - if (gl === null) { - console.error("Unable to initialise WebGL"); - return; - } - - console.info("Successfully opened webgl canvas"); - - let x; - let y; - let width; - let height; - - // A nice pink to show missing values - gl.clearColor(1.0, 0.753, 0.796, 1.0); - gl.clearDepth(1.0); - gl.enable(gl.DEPTH_TEST); - gl.depthFunc(gl.LEQUAL); - gl.disable(gl.CULL_FACE); - gl.lineWidth(1.0); - - const xBuffer = gl.createBuffer(); - const yBuffer = gl.createBuffer(); - const lineDrawer = new LineDrawer(gl); - - function setup() { - width = parseInt(document.getElementById("xN").value); - height = parseInt(document.getElementById("yN").value); - - const x0 = parseFloat(document.getElementById("x0").value); - const xn = parseFloat(document.getElementById("xn").value); - const y0 = parseFloat(document.getElementById("y0").value); - const yn = parseFloat(document.getElementById("yn").value); - - const diamond = document.getElementById("diamond").checked; - console.log(diamond); - - x = new Float32Array(width * height); - y = new Float32Array(width * height); - const dx = (xn - x0) / (width - 1) - const dy = (yn - y0) / (height - 1) - for (let j = 0; j < height; j += 1) { - for (let i = 0; i < width; i += 1) { - const n = width*j + i; - x[n] = dx*i; - y[n] = dy*j; - - if (diamond) { - const xn = x[n]; - const yn = y[n]; - - x[n] = xn - yn; - y[n] = xn + yn; - } - } - } - - const bbox = [+Number(Infinity), -Number(Infinity), +Number(Infinity), -Number(Infinity)]; - for (let i = 0; i < width*height; i += 1) { - bbox[0] = Math.min(bbox[0], x[i]); - bbox[1] = Math.max(bbox[1], x[i]); - bbox[2] = Math.min(bbox[2], y[i]); - bbox[3] = Math.max(bbox[3], y[i]); - } - gl.bindBuffer(gl.ARRAY_BUFFER, xBuffer); - gl.bufferData(gl.ARRAY_BUFFER, x, gl.STATIC_DRAW); - gl.bindBuffer(gl.ARRAY_BUFFER, yBuffer); - gl.bufferData(gl.ARRAY_BUFFER, y, gl.STATIC_DRAW); - - lineDrawer.set_xy(width, height, xBuffer, yBuffer, bbox); - } - - function draw() { - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - - lineDrawer.draw(); - } - - function drawMe() { - draw(); - animation = window.requestAnimationFrame(drawMe); - } - - function resizeCanvas() { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - - gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); - } - - - resizeCanvas(); - window.addEventListener("resize", resizeCanvas, false); - - const menu = document.getElementById("menu"); - const menu_toggle = document.getElementById("toggle-menu"); - menu_toggle.addEventListener("click", () => { - if (menu.style.visibility === "") { - menu.style.visibility = "hidden"; - } else { - menu.style.visibility = ""; - } - }); - - eq_sel.addEventListener("change", (e) => { - console.log("equation changed, wants: ", e.target.value); - display_eqset(eq_sel.value); - }); - function display_eqset(value) { - const euler_options = document.getElementById("euler-options"); - euler_options.style.display = "none"; - const maxwell_options = document.getElementById("maxwell-options"); - maxwell_options.style.display = "none"; - const shallow_options = document.getElementById("shallow-options"); - shallow_options.style.display = "none"; - if (value === "euler") { - euler_options.style.display = "block"; - } else if (value === "maxwell") { - maxwell_options.style.display = "block"; - } else if (value === "shallow") { - shallow_options.style.display = "block"; - } else { - console.error(`Unknown value ${value}`); - } - } - - let animation = null; - let is_setup = false; - const play_button = document.getElementById("toggle-playing"); - play_button.addEventListener("click", (_e) => { - console.log("play/pause pressed"); - if (!animation) { - if (!is_setup) { - setup(); - } - animation = window.requestAnimationFrame(drawMe); - } else { - window.cancelAnimationFrame(animation); - animation = null; - } - }); - const reset_button = document.getElementById("reset"); - reset_button.addEventListener("click", (_e) => { - window.cancelAnimationFrame(animation); - animation = null; - is_setup = false; - setup(); - draw(); - }); -}()); diff --git a/webfront/pages/index.html b/webfront/pages/index.html index 9a4f750..b145e1e 100644 --- a/webfront/pages/index.html +++ b/webfront/pages/index.html @@ -50,9 +50,11 @@ Curvilinear? Inputting some random json? --> + diff --git a/webfront/pages/main.js b/webfront/pages/main.js index 8d64ce2..cece613 100644 --- a/webfront/pages/main.js +++ b/webfront/pages/main.js @@ -49,7 +49,7 @@ class LineDrawer { #version 100 void main() { - gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0); + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); } `; const program = compile_and_link(ctx, LINE_VERTEX_SHADER, LINE_FRAGMENT_SHADER); @@ -63,18 +63,8 @@ class LineDrawer { } set_xy(width, height, xBuffer, yBuffer, bbox) { const ctx = this.ctx; - ctx.useProgram(this.program.inner); - { - let loc = ctx.getAttribLocation(this.program.inner, "aX"); - ctx.bindBuffer(ctx.ARRAY_BUFFER, xBuffer); - ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); - ctx.enableVertexAttribArray(loc); - - loc = ctx.getAttribLocation(this.program.inner, "aY"); - ctx.bindBuffer(ctx.ARRAY_BUFFER, yBuffer); - ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); - ctx.enableVertexAttribArray(loc); - } + this.xBuffer = xBuffer; + this.yBuffer = yBuffer; const lineIdxBuffer = new Uint16Array(2*width*height - 1); { let n = 0; @@ -128,6 +118,7 @@ class LineDrawer { ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, lineIdxBuffer, ctx.STATIC_DRAW); + ctx.useProgram(this.program.inner); ctx.uniform4f(this.program.uniforms.uBbox, bbox[0], 1.0/(bbox[1] - bbox[0]), bbox[2], 1.0/(bbox[3] - bbox[2])); this.width = width; this.height = height; @@ -135,6 +126,18 @@ class LineDrawer { draw() { const ctx = this.ctx; ctx.useProgram(this.program.inner); + { + let loc; + loc = ctx.getAttribLocation(this.program.inner, "aX"); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.xBuffer); + ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); + ctx.enableVertexAttribArray(loc); + + loc = ctx.getAttribLocation(this.program.inner, "aY"); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.yBuffer); + ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); + ctx.enableVertexAttribArray(loc); + } ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); ctx.drawElements(ctx.LINE_STRIP, 2*this.width*this.height - 1, ctx.UNSIGNED_SHORT, 0); @@ -144,13 +147,113 @@ class LineDrawer { class FieldDrawer { constructor(ctx) { this.ctx = ctx; - this.fbuffer = ctx.createBuffer(); - //link_and_bind_program(.., ..); + const VERT_SHADER = String.raw` + #version 100 + attribute mediump float aX; + attribute mediump float aY; + attribute mediump float aField; + + uniform vec4 uBbox; + + varying mediump float vField; + + void main() { + vField = aField; + mediump float x = (aX - uBbox.x)*uBbox.y; + mediump float y = (aY - uBbox.z)*uBbox.w; + gl_Position = vec4(2.0*x - 1.0, 2.0*y - 1.0, 1.0, 1.0); + } + `; + + const FRAG_SHADER = String.raw` + #version 100 + varying mediump float vField; + + uniform mediump vec3 uColor; + uniform mediump float uFieldMin; + uniform mediump float uFieldMax; + + void main() { + mediump float v = (vField - uFieldMin) / (uFieldMax - uFieldMin); + gl_FragColor = vec4(mix(vec3(0.0), uColor, v), 1.0); + } + `; + + const program = compile_and_link(ctx, VERT_SHADER, FRAG_SHADER); + this.fBuffer = ctx.createBuffer(); + + const uniforms = { + uBbox: ctx.getUniformLocation(program, "uBbox"), + uColor: ctx.getUniformLocation(program, "uColor"), + uFieldMin: ctx.getUniformLocation(program, "uFieldMin"), + uFieldMax: ctx.getUniformLocation(program, "uFieldMax"), + }; + + this.program = {inner: program, uniforms: uniforms}; + } + set_xy(width, height, xBuffer, yBuffer, bbox) { + const ctx = this.ctx; + this.xBuffer = xBuffer; + this.yBuffer = yBuffer; + ctx.useProgram(this.program.inner); + ctx.uniform4f(this.program.uniforms.uBbox, bbox[0], 1.0/(bbox[1] - bbox[0]), bbox[2], 1.0/(bbox[3] - bbox[2])); + this.setColor(0.0, 1.0, 0.0); + + const positions = new Uint16Array((width-1)*(height-1)*2*3); + for (let j = 0; j < height - 1; j += 1) { + for (let i = 0; i < width - 1; i += 1) { + const n = 2*3*((width-1)*j + i); + positions[n+0] = width*j + i; + positions[n+1] = width*j + i+1; + positions[n+2] = width*(j+1) + i; + positions[n+3] = width*j + i+1; + positions[n+4] = width*(j+1) + i; + positions[n+5] = width*(j+1) + i+1; + } + } + this.positions = positions; + this.indexBuffer = ctx.createBuffer(); + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, this.positions, ctx.STATIC_DRAW); + } + setColor() { + this.ctx.uniform3f(this.program.uniforms.uColor, 0.0, 1.0, 0.0); + } + draw(field) { + const ctx = this.ctx; + ctx.useProgram(this.program.inner); + { + let loc; + loc = ctx.getAttribLocation(this.program.inner, "aX"); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.xBuffer); + ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); + ctx.enableVertexAttribArray(loc); + + loc = ctx.getAttribLocation(this.program.inner, "aY"); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.yBuffer); + ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); + ctx.enableVertexAttribArray(loc); + + loc = ctx.getAttribLocation(this.program.inner, "aField"); + ctx.bindBuffer(ctx.ARRAY_BUFFER, this.fBuffer); + ctx.bufferData(ctx.ARRAY_BUFFER, field, ctx.DYNAMIC_DRAW); + ctx.vertexAttribPointer(loc, 1, ctx.FLOAT, false, 0, 0); + ctx.enableVertexAttribArray(loc); + } + + ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, this.indexBuffer); + ctx.drawElements(ctx.TRIANGLES, this.positions.length, ctx.UNSIGNED_SHORT, 0); + } + minmax(min, max) { + this.ctx.useProgram(this.program.inner); + this.ctx.uniform1f(this.program.uniforms.uFieldMin, min); + this.ctx.uniform1f(this.program.uniforms.uFieldMax, max); } } (async function run() { + let is_setup = false; const eq_sel = document.getElementById("eq-set"); display_eqset(eq_sel.value); @@ -170,6 +273,7 @@ class FieldDrawer { let y; let width; let height; + const bbox = [+Number(Infinity), -Number(Infinity), +Number(Infinity), -Number(Infinity)]; // A nice pink to show missing values gl.clearColor(1.0, 0.753, 0.796, 1.0); @@ -182,8 +286,11 @@ class FieldDrawer { const xBuffer = gl.createBuffer(); const yBuffer = gl.createBuffer(); const lineDrawer = new LineDrawer(gl); + const fieldDrawer = new FieldDrawer(gl); let universe; + let eq_set; + function setup() { width = parseInt(document.getElementById("xN").value); height = parseInt(document.getElementById("yN").value); @@ -202,8 +309,8 @@ class FieldDrawer { for (let j = 0; j < height; j += 1) { for (let i = 0; i < width; i += 1) { const n = width*j + i; - x[n] = dx*i; - y[n] = dy*j; + x[n] = x0 + dx*i; + y[n] = y0 + dy*j; if (diamond) { const xn = x[n]; @@ -215,23 +322,29 @@ class FieldDrawer { } } - const eq_set = eq_sel.value; + eq_set = eq_sel.value; switch (eq_set) { case "maxwell": universe = new MaxwellUniverse(height, width, x, y); + universe.init(0.0, 0.0); break; case "euler": - universe = new EulerUniverse(); + universe = new EulerUniverse(height, width, x, y); + universe.init(0.0, 0.0); break; case "shallow": - universe = new ShallowWaterUniverse(); + universe = new ShallowWaterUniverse(height, width); + universe.init(0.0, 0.0); break; default: console.error(`Unknown case ${eq_set}`); return null; } - const bbox = [+Number(Infinity), -Number(Infinity), +Number(Infinity), -Number(Infinity)]; + bbox[0] = +Number(Infinity); + bbox[1] = -Number(Infinity); + bbox[2] = +Number(Infinity); + bbox[3] = -Number(Infinity); for (let i = 0; i < width*height; i += 1) { bbox[0] = Math.min(bbox[0], x[i]); bbox[1] = Math.max(bbox[1], x[i]); @@ -244,22 +357,99 @@ class FieldDrawer { gl.bufferData(gl.ARRAY_BUFFER, y, gl.STATIC_DRAW); lineDrawer.set_xy(width, height, xBuffer, yBuffer, bbox); + fieldDrawer.set_xy(width, height, xBuffer, yBuffer, bbox); } function draw() { gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - lineDrawer.draw(); - } - - function drawMe() { const w = canvas.clientWidth; const h = canvas.clientHeight; canvas.width = w; canvas.height = h; gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); + + let fieldPtr; + switch (eq_set) { + case "maxwell": + chosenField %= 3; + switch (chosenField) { + case 0: + fieldPtr = universe.get_ex_ptr(); + fieldDrawer.minmax(-1.0, 1.0); + break; + case 1: + fieldPtr = universe.get_hz_ptr(); + fieldDrawer.minmax(-1.0, 1.0); + break; + case 2: + fieldPtr = universe.get_ey_ptr(); + fieldDrawer.minmax(-1.0, 1.0); + break; + } + break; + case "euler": + chosenField %= 4; + switch (chosenField) { + case 0: + fieldPtr = universe.get_rho_ptr(); + fieldDrawer.minmax(0.95, 1.05); + break; + case 1: + fieldPtr = universe.get_rhou_ptr(); + fieldDrawer.minmax(0.90, 1.10); + break; + case 2: + fieldPtr = universe.get_rhov_ptr(); + fieldDrawer.minmax(-1.10, 1.10); + break; + case 3: + fieldPtr = universe.get_e_ptr(); + fieldDrawer.minmax(7.0, 10.0); + break; + } + break; + case "shallow": + chosenField %= 3; + switch (chosenField) { + case 0: + fieldPtr = universe.get_eta_ptr(); + fieldDrawer.minmax(0.8, 1.1); + break; + case 1: + fieldPtr = universe.get_etau_ptr(); + fieldDrawer.minmax(-0.5, 0.5); + break; + case 2: + fieldPtr = universe.get_etav_ptr(); + fieldDrawer.minmax(-0.5, 0.5); + break; + } + break; + default: + console.error("Not implemented"); + } + let field = new Float32Array(wasm.memory.buffer, fieldPtr, width*height); + fieldDrawer.draw(field); + lineDrawer.draw(); + } + + async function drawLoop() { draw(); - animation = window.requestAnimationFrame(drawMe); + switch (eq_set) { + case "maxwell": + universe.advance(0.2*Math.min(1/width, 1/height)); + break; + case "euler": + universe.advance_upwind(0.2*Math.min(1/width, 1/height)); + break; + case "shallow": + universe.advance(); + break; + default: + console.error(`Not implemented: ${eq_set}`); + } + animation = window.requestAnimationFrame(drawLoop); } const menu = document.getElementById("menu"); @@ -270,11 +460,11 @@ class FieldDrawer { } else { menu.style.visibility = ""; } - }); + }, {"passive": false}); eq_sel.addEventListener("change", (e) => { display_eqset(eq_sel.value); - }); + }, {"passive": true}); function display_eqset(value) { const euler_options = document.getElementById("euler-options"); euler_options.style.display = "none"; @@ -282,37 +472,67 @@ class FieldDrawer { maxwell_options.style.display = "none"; const shallow_options = document.getElementById("shallow-options"); shallow_options.style.display = "none"; + function default_axes(x0, xn, y0, yn) { + document.getElementById("x0").value = x0; + document.getElementById("xn").value = xn; + document.getElementById("y0").value = y0; + document.getElementById("yn").value = yn; + } if (value === "euler") { euler_options.style.display = "block"; + default_axes(-5.0, 5.0, -5.0, 5.0); } else if (value === "maxwell") { maxwell_options.style.display = "block"; + default_axes(-1.0, 1.0, -1.0, 1.0); } else if (value === "shallow") { shallow_options.style.display = "block"; + default_axes(-1.0, 1.0, -1.0, 1.0); } else { console.error(`Unknown value ${value}`); } + is_setup = false; } let animation = null; - let is_setup = false; const play_button = document.getElementById("toggle-playing"); play_button.addEventListener("click", (_e) => { if (!animation) { if (!is_setup) { setup(); + is_setup = true; } - animation = window.requestAnimationFrame(drawMe); + animation = window.requestAnimationFrame(drawLoop); } else { + if (is_setup) { + window.cancelAnimationFrame(animation); + animation = null; + } + } + }, {"passive": true}); + const reset_button = document.getElementById("reset"); + reset_button.addEventListener("click", (_e) => { + if (is_setup) { window.cancelAnimationFrame(animation); animation = null; } - }); - const reset_button = document.getElementById("reset"); - reset_button.addEventListener("click", (_e) => { - window.cancelAnimationFrame(animation); - animation = null; - is_setup = false; setup(); + is_setup = true; draw(); - }); + }, {"passive": true}); + let chosenField = 0; + const chosenFieldButton = document.getElementById("fieldButton"); + chosenFieldButton.addEventListener("click", (_e) => { + chosenField += 1; + if (is_setup) { + draw(); + } + }, {"passive": true}); + canvas.addEventListener("click", (e) => { + if (is_setup) { + const mousex = (e.clientX / canvas.clientWidth)*(bbox[1] - bbox[0]) + bbox[0]; + const mousey = (1.0 - e.clientY / canvas.clientHeight)*(bbox[3] - bbox[2]) + bbox[2]; + universe.init(mousex, mousey); + draw(); + } + }, {"passive": false}); }()); diff --git a/webfront/pages/style.css b/webfront/pages/style.css index 84d8b3e..b0d2e8f 100644 --- a/webfront/pages/style.css +++ b/webfront/pages/style.css @@ -1,10 +1,10 @@ * { margin: 0; padding: 0; overflow: hidden; } html, body { width:100%; height:100%; } -canvas { display:block; position: fixed; z-index: -1; width: 100vw; height: 100vh; } +canvas { display:block; position: fixed; width: 100vw; height: 100vh; } select#eq-set { width: 100%; } .vertical-menu { position: fixed; width: 30%; min-width: 200px; top: 0; bottom: 30px; z-index: 2; background-color: #eee; display: flex; flex-direction: column; justify-content: space-between; padding: 0.5em; overflow-y: auto; } .menu-header { font-weight: bold; } -.controls { position: relative; z-index: 3; top: calc(100% - 30px); height: 30px; display: flex; align-items: center; width: 175px; justify-content: space-around; opacity: 0.5; } +.controls { position: relative; z-index: 3; top: calc(100% - 30px); height: 30px; display: flex; align-items: center; width: 100%; justify-content: flex-start; opacity: 0.5; } .controls:hover { opacity: 1.0; } .menu-item { flex-shrink: 0; } .horizontal-flex { display: flex; flex-direction: row; align-items: center; justify-content: space-between; }