From 638acfc48f4ecea297123936eb2483fa9b712c7d Mon Sep 17 00:00:00 2001 From: Logan Hunt Date: Wed, 8 Jun 2022 01:57:28 -0700 Subject: [PATCH] Better mouse movement; add custom input box --- julia/index.html | 8 ++-- julia/julia.js | 102 +++++++++++++++++++++-------------------------- 2 files changed, 49 insertions(+), 61 deletions(-) diff --git a/julia/index.html b/julia/index.html index 312e3f6..5b4c90d 100644 --- a/julia/index.html +++ b/julia/index.html @@ -36,11 +36,11 @@
- imaginary: - + imaginary: +
- real: - + real: +
powered by gpu.js diff --git a/julia/julia.js b/julia/julia.js index d5e6bba..dd61137 100644 --- a/julia/julia.js +++ b/julia/julia.js @@ -1,6 +1,7 @@ const MIN_ZOOM = 0.0001; const MAX_ZOOM = 4; -const SLIDER_DIV = 1000; +const C_THRESHOLD = Math.sqrt(2)/2; +const SLIDER_DIV = 1000*C_THRESHOLD; const gpu = new GPU(); const buildRender = (width, height) => gpu.createKernel(function (maxIterations, cr, ci, centerX, centerY, zoom, colorMultipliers) { @@ -11,9 +12,6 @@ const buildRender = (width, height) => gpu.createKernel(function (maxIterations, const xtemp = zx * zx - zy * zy + cr; zy = 2 * zx * zy + ci; zx = xtemp; - - // filled Julia set for Q_c exists only when z has radius less than 2 and less than |c| - // and we are only allowing |c| < 2 if (zx * zx + zy * zy > 4) { iterations = i; break; @@ -29,13 +27,13 @@ const buildRender = (width, height) => gpu.createKernel(function (maxIterations, const canvasHolder = document.getElementById('canvasHolder'); let render; // The GPU kernel built from buildRender let state = { - colorMultipliers: [0.01 * Math.random() + 0.005, 0.03 * Math.random() + 0.005, 0.02 * Math.random() + 0.005], + colorMultipliers: [0.01 * Math.random() + 0.015, 0.03 * Math.random() + 0.007, 0.02 * Math.random() + 0.010], changes: { centerX: 0, centerY: 0, zoom: 3, - cr: parseFloat(document.getElementById("realSlider").value) / SLIDER_DIV, - ci: parseFloat(document.getElementById("imaginarySlider").value) / SLIDER_DIV, + cr: parseFloat(document.getElementById('realSlider').value) / SLIDER_DIV, + ci: parseFloat(document.getElementById('imaginarySlider').value) / SLIDER_DIV, maxIterations: 1000, width: document.body.clientWidth, height: document.body.clientHeight, @@ -43,6 +41,7 @@ let state = { }; const doRender = (renderF, state) => { + // gpu.js doesn't support JS objects as kernel parameters - https://github.com/gpujs/gpu.js/issues/245 renderF(state.maxIterations, state.cr, state.ci, state.centerX, state.centerY, state.zoom, state.colorMultipliers); }; @@ -54,11 +53,13 @@ const loop = () => { render = buildRender(state.width, state.height); canvasHolder.appendChild(render.canvas); } - if (state.changes.ci !== undefined) { - document.getElementById("imag-val").innerHTML = state.ci.toFixed(4); + if (typeof state.changes.ci !== 'undefined') { + document.getElementById('imag-val').value = state.ci.toFixed(4); + document.getElementById('imaginarySlider').value = state.changes.ci * SLIDER_DIV; } - if (state.changes.cr !== undefined) { - document.getElementById("real-val").innerHTML = state.cr.toFixed(4); + if (typeof state.changes.cr !== 'undefined') { + document.getElementById('real-val').value = state.cr.toFixed(4); + document.getElementById('realSlider').value = state.changes.cr * SLIDER_DIV; } state.changes = {}; doRender(render, state); @@ -71,72 +72,59 @@ loop(); // NOTE: UI code is trash lol -const startImagAnim = () => { +const startAnim = (sliderId, complexComponentName='ci') => { + const restart = (interval) => { + clearInterval(interval); + document.getElementById(sliderId).innerHTML = 'Animate'; + document.getElementById(sliderId).onclick = ()=>startAnim(sliderId, complexComponentName); + return; + }; const start = setInterval(() => { - if (state.ci >= 1) { - clearInterval(start); - document.getElementById("animate-imag").innerHTML = "Animate"; - document.getElementById("animate-imag").onclick = startImagAnim; - return; + if (state[complexComponentName] >= C_THRESHOLD) { + restart(start); } - state.changes.ci = state.ci + 0.001; - document.getElementById("imaginarySlider").value = state.changes.ci * 1000; + state.changes[complexComponentName] = state[complexComponentName] + 0.001; }, 1000/60); - document.getElementById("animate-imag").innerHTML = "Stop"; - document.getElementById("animate-imag").onclick = () => { - clearInterval(start); - document.getElementById("animate-imag").innerHTML = "Animate"; - document.getElementById("animate-imag").onclick = startImagAnim; - }; + document.getElementById(sliderId).innerHTML = 'Stop'; + document.getElementById(sliderId).onclick = ()=>restart(start); }; -const startRealAnim = () => { - const start = setInterval(() => { - if (state.cr >= 1) { - clearInterval(start); - document.getElementById("animate-real").innerHTML = "Animate"; - document.getElementById("animate-real").onclick = startRealAnim; - return; - } - - state.changes.cr = state.cr + 0.001; - document.getElementById("realSlider").value = state.changes.cr * 1000; - }, 1000/60); - document.getElementById("animate-real").innerHTML = "Stop"; - document.getElementById("animate-real").onclick = () => { - clearInterval(start); - document.getElementById("animate-real").innerHTML = "Animate"; - document.getElementById("animate-real").onclick = startRealAnim; - }; -}; - -document.getElementById("realSlider").oninput = function() { +document.getElementById('realSlider').oninput = function() { state.changes.cr = parseFloat(this.value) / SLIDER_DIV; }; - -document.getElementById("imaginarySlider").oninput = function() { +document.getElementById('imaginarySlider').oninput = function() { state.changes.ci = parseFloat(this.value) / SLIDER_DIV; }; -canvasHolder.onwheel = (event) => { - state.changes.zoom = Math.min(Math.max(state.zoom + event.deltaY * 0.001 * state.zoom, MIN_ZOOM), MAX_ZOOM); -} +document.getElementById('imag-val').addEventListener('change', function (e) { + state.changes.ci = parseFloat(this.value); +}); +document.getElementById('real-val').addEventListener('change', function (e) { + state.changes.cr = parseFloat(this.value); +}); + +canvasHolder.addEventListener('wheel', (e) => { + e.preventDefault(); + state.changes.zoom = Math.min(Math.max(state.zoom + e.deltaY * 0.001 * state.zoom, MIN_ZOOM), MAX_ZOOM); +}); let isDown = false; -canvasHolder.addEventListener('mousedown', function(e) { +canvasHolder.addEventListener('mousedown', (e) => { + e.preventDefault(); isDown = true; }, true); -canvasHolder.addEventListener('mouseup', function() { +canvasHolder.addEventListener('mouseup', (e) => { + e.preventDefault(); isDown = false; }, true); -canvasHolder.addEventListener('mousemove', function(event) { - event.preventDefault(); +canvasHolder.addEventListener('mousemove', (e) => { + e.preventDefault(); if (isDown) { - let deltaX = -event.movementX * state.zoom / 700; - let deltaY = event.movementY * state.zoom / 700; + let deltaX = -e.movementX * state.zoom / document.body.clientWidth; + let deltaY = e.movementY * state.zoom / document.body.clientHeight; state.changes.centerX = state.centerX + deltaX; state.changes.centerY = state.centerY + deltaY; }