Draw the slope field of a 1st order ODE and add object (type or click) to trace the equation.
R=Z=16;L=[-2,2,-2,-2];b.innerHTML="dy/dx=<input id=f value='x/2/y+y/2/x'> <input type=checkbox checked onclick=R=this.checked>trail <button onclick=L=[]>clear object</button> <input id=h><button id=m>add</button><br><canvas id=e></canvas>";e.width=S=512;e.height=S;e.style.width=S+"px";e.style.height=S+"px";o=e.getContext("2d");with(Math)F=(x,y)=>eval(f.value),V=s=>([1/(u=sqrt(s*s+1)),s/u]);M=(i,p,q,x,y)=>(i-p)*(y-x)/(q-p)+x;(B=_=>{o.fillStyle="#fff";o.fillRect(0,0,S,S);o.strokeStyle="#48e";for(i=0;i<S;i+=Z)for(j=0;j<S;j+=Z)r=V(F(M(p=i+8,0,S,-2,2),M(q=j+8,0,S,2,-2))),s=r[0]*8,t=r[1]*8,o.beginPath(),o.moveTo(p-s,q+t),o.lineTo(p+s,q-t),o.stroke()})();setInterval('for(!R&&B(),o.fillStyle="#e44",i=0;i<S;i++)for(j=0;j<L.length;j+=2)if(L[j]<2)p=V(F(L[j],L[j+1])),L[j]+=p[0]/5e3,L[j+1]+=p[1]/5e3,o.fillRect(M(L[j],-2,2,0,S)-1,M(L[j+1],-2,2,S,0)-1,2,2)');e.onclick=i=>L.push(M(i.pageX-e.offsetLeft,0,S,-2,2),M(i.pageY-e.offsetTop,0,S,2,-2));f.oninput=_=>B(L=[]);m.onclick=(p,l=h.value.split(","))=>L.push(l[0]*1,l[1]*1)
Uj1aPTE2O0w9Wy0yLDIsLTIsLTJdO2IuaW5uZXJIVE1MPSJkeS9keD08aW5wdXQgaWQ9ZiB2YWx1ZT0neC8yL3kreS8yL3gnPiA8aW5wdXQgdHlwZT1jaGVja2JveCBjaGVja2VkIG9uY2xpY2s9Uj10aGlzLmNoZWNrZWQ+dHJhaWwgPGJ1dHRvbiBvbmNsaWNrPUw9W10+Y2xlYXIgb2JqZWN0PC9idXR0b24+IDxpbnB1dCBpZD1oPjxidXR0b24gaWQ9bT5hZGQ8L2J1dHRvbj48YnI+PGNhbnZhcyBpZD1lPjwvY2FudmFzPiI7ZS53aWR0aD1TPTUxMjtlLmhlaWdodD1TO2Uuc3R5bGUud2lkdGg9UysicHgiO2Uuc3R5bGUuaGVpZ2h0PVMrInB4IjtvPWUuZ2V0Q29udGV4dCgiMmQiKTt3aXRoKE1hdGgpRj0oeCx5KT0+ZXZhbChmLnZhbHVlKSxWPXM9PihbMS8odT1zcXJ0KHMqcysxKSkscy91XSk7TT0oaSxwLHEseCx5KT0+KGktcCkqKHkteCkvKHEtcCkreDsoQj1fPT57by5maWxsU3R5bGU9IiNmZmYiO28uZmlsbFJlY3QoMCwwLFMsUyk7by5zdHJva2VTdHlsZT0iIzQ4ZSI7Zm9yKGk9MDtpPFM7aSs9Wilmb3Ioaj0wO2o8UztqKz1aKXI9VihGKE0ocD1pKzgsMCxTLC0yLDIpLE0ocT1qKzgsMCxTLDIsLTIpKSkscz1yWzBdKjgsdD1yWzFdKjgsby5iZWdpblBhdGgoKSxvLm1vdmVUbyhwLXMscSt0KSxvLmxpbmVUbyhwK3MscS10KSxvLnN0cm9rZSgpfSkoKTtzZXRJbnRlcnZhbCgnZm9yKCFSJiZCKCksby5maWxsU3R5bGU9IiNlNDQiLGk9MDtpPFM7aSsrKWZvcihqPTA7ajxMLmxlbmd0aDtqKz0yKWlmKExbal08MilwPVYoRihMW2pdLExbaisxXSkpLExbal0rPXBbMF0vNWUzLExbaisxXSs9cFsxXS81ZTMsby5maWxsUmVjdChNKExbal0sLTIsMiwwLFMpLTEsTShMW2orMV0sLTIsMixTLDApLTEsMiwyKScpO2Uub25jbGljaz1pPT5MLnB1c2goTShpLnBhZ2VYLWUub2Zmc2V0TGVmdCwwLFMsLTIsMiksTShpLnBhZ2VZLWUub2Zmc2V0VG9wLDAsUywyLC0yKSk7Zi5vbmlucHV0PV89PkIoTD1bXSk7bS5vbmNsaWNrPShwLGw9aC52YWx1ZS5zcGxpdCgiLCIpKT0+TC5wdXNoKGxbMF0qMSxsWzFdKjEp
// JS1K ENTRY
// Title: 1st Order ODE Graph
// by Muhammad Rifqi Priyo Susanto
// R = do objects leave trails? (default: true)
// Z = grid size
// L = list of points: x, y (for graph)
// L contains initial objects to show "X".
R = Z = 16;
L = [-2, 2, -2, -2];
// Add elements for GUI.
// Initial y'(x) will make initial objects move to create "X".
b.innerHTML="dy/dx=<input id=f value='x/2/y+y/2/x'> <input type=checkbox checked onclick=R=this.checked>trail <button onclick=L=[]>clear object</button> <input id=h><button id=m>add</button><br><canvas id=e></canvas>";
// The canvas' size is fixed to 512 px with 16 px grid.
// The graph's viewport is from (-2, -2) to (2, 2).
// Number 8 is calculated from half of grid's size.
// Number -2 and 2 is from graph's viewport.
e.width = S = 512;
e.height = S;
e.style.width = S + "px";
e.style.height = S + "px";
o = e.getContext("2d");
// Some functions to do with drawing graph
// with(Math) is used to make typing only cos() and not Math.cos()
// possible also to shorten Math.sqrt() to sqrt().
with (Math)
F = (x, y) => eval(f.value), // dy/dx or f(x, y)
V = s => ([1 / (u = sqrt(s * s + 1)), s / u]); // slope to unit vector
M = (i, p, q, x, y) => (i - p) * (y - x) / (q - p) + x; // mapping function
// Function to draw slope field of the ODE
// This function will clear the canvas before drawing.
(B = _ => {
o.fillStyle = "#fff";
o.fillRect(0, 0, S, S);
o.strokeStyle = "#48e";
for (i = 0; i < S; i += Z)
for (j = 0; j < S; j += Z)
r = V(F(M(p = i + 8, 0, S, -2, 2),
M(q = j + 8, 0, S, 2, -2))),
s = r[0] * 8,
t = r[1] * 8,
o.beginPath(),
o.moveTo(p - s, q + t),
o.lineTo(p + s, q - t),
o.stroke()
})();
// Function to draw and move objects
setInterval(_ => {
// If the objects don't leave trails, redraw the slope field.
// Calculate movements by walking in tiny steps.
for (!R && B(), o.fillStyle = "#e44", i = 0; i < S; i ++)
for (j = 0; j < L.length; j += 2)
if(L[j] < 2) // Don't draw past viewport.
p = V(F(L[j], L[j + 1])),
L[j] += p[0] / 5e3,
L[j + 1] += p[1] / 5e3,
o.fillRect(M(L[j], -2, 2, 0, S) - 1,
M(L[j + 1], -2, 2, S, 0) - 1, 2, 2)
});
// Some event handler functions
// We can click the canvas to add new object instead of typing coordinates.
e.onclick = i => L.push(M(i.pageX - e.offsetLeft, 0, S, -2, 2), M(i.pageY - e.offsetTop, 0, S, 2, -2));
// Remove all objects and redraw the slope field when the ODE is changed.
f.oninput = _ => B(L = []);
// Add new object from typed coordinates.
m.onclick = (p, l = h.value.split(",")) => L.push(l[0] * 1, l[1] * 1)