Skip to content

Instantly share code, notes, and snippets.

@ceylonwebide
Last active August 13, 2017 15:09
Show Gist options
  • Save ceylonwebide/bd41b47f325b6d32514a to your computer and use it in GitHub Desktop.
Save ceylonwebide/bd41b47f325b6d32514a to your computer and use it in GitHub Desktop.
Ceylon Web Runner: Solar System

Ceylon Solar System Example

This little example application demonstrates the use of Ceylon as an alternative to client-side JavaScript. In particular, the example shows:

  • a simple, typesafe, object-oriented program,
  • dependence on an external cross-platform math module written in Ceylon and hosted on Ceylon Herd,
  • interoperation with a JavaScript API (the HTML canvas) via a dynamic interface that ascribes static types to the API, and
  • direct calls to dynamically typed JavaScript in a dynamic block.

To run this code, just click the 'Run' button above. Then browse the code in the other tabs.

Have fun!

This code is adapted from:

https://developer.mozilla.org/en-US/demos/detail/sistema-solar

import ceylon.numeric.float {
pi, cos, sin
}
"An astronomical body in 2 dimensions."
interface Body {
"The position on the x axis."
shared formal Float x;
"The position on the y axis."
shared formal Float y;
"The radius of the object."
shared formal Float r;
"Draw the object."
shared formal void draw(CanvasRenderingContext2D ctx);
"Move the object in its orbit."
shared formal void orbit();
}
"The sun."
class Sun(x, y, r, String color)
satisfies Body {
shared actual Float x;
shared actual Float y;
shared actual Float r;
draw = (CanvasRenderingContext2D ctx) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, r, 0.0, pi * 2.0, true);
ctx.closePath();
ctx.fill();
};
orbit = noop;
}
"A planet or moon."
class Planet(name, primary, r, Float v, String color = "#FFF",
rp = 0.0, String? ringColor = null)
satisfies Body {
shared String name;
shared Body primary;
shared actual Float r;
"Distance to the primary. (Radius of the orbit.)"
shared Float rp;
shared actual variable Float x = primary.x;
shared actual variable Float y = primary.y - rp - (r + primary.r);
variable Float radian = pi/2;
orbit = () {
radian += v / 360.0 * pi;
x = primary.x - sin(radian) * (primary.r + rp);
y = primary.y + cos(radian) * (primary.r + rp);
};
draw = (CanvasRenderingContext2D ctx) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, r, 0.0, pi * 2.0, true);
ctx.closePath();
ctx.fill();
if (exists ringColor) {
ctx.strokeStyle = ringColor;
ctx.lineWidth = r * 0.75;
ctx.beginPath();
ctx.arc(x, y, r * 1.6, 0.0, pi * 2.0, true);
ctx.closePath();
ctx.stroke();
}
};
}
alias Number => Integer|Float;
"Ascribes static types to the operations of the HTML
canvas context. Note that this is not necessary,
since we could access the canvas in a dynamic block,
but it makes the code more typesafe."
dynamic CanvasRenderingContext2D {
shared formal variable String fillStyle;
shared formal variable String strokeStyle;
shared formal variable Number lineWidth;
shared formal variable String font;
shared formal void beginPath();
shared formal void closePath();
shared formal void moveTo(Number x, Number y);
shared formal void lineTo(Number x, Number y);
shared formal void fill();
shared formal void stroke();
shared formal void fillText(String text, Number x, Number y, Number maxWidth=-1);
shared formal void arc(Number x, Number y, Number radius, Number startAngle, Number endAngle, Boolean anticlockwise);
shared formal void arcTo(Number x1, Number y1, Number x2, Number y2, Number radius);
shared formal void bezierCurveTo(Number cp1x, Number cp1y, Number cp2x, Number cp2y, Number x, Number y);
shared formal void strokeRect(Number x, Number y, Number width, Number height);
shared formal void fillRect(Number x, Number y, Number width, Number height);
shared formal void clearRect(Number x, Number y, Number width, Number height);
//TODO: more operations!!
}
"The program entry point."
shared void run() {
print("Starting...");
variable value stopped = false;
Integer width;
Integer height;
CanvasRenderingContext2D ctx;
dynamic {
//direct calls to JavaScipt with
//dynamic typing
dynamic win = openCanvasWindow();
dynamic canvas = win.ceylonCanvas;
width = canvas.scrollWidth;
height = canvas.scrollHeight;
canvas.width = width;
canvas.height = height;
ctx = canvas.getContext("2d");
setOnStop(() => stopped = true);
}
value system = createSystem(width, height);
value [sol, *planets] = system;
value labels
= " | ".join {
for (planet in planets)
if (planet.primary==sol)
planet.name + ":" +
formatFloat(planet.rp,0,0)
};
variable value time = 0;
void paint() {
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, width, height);
for (body in system) {
body.draw(ctx);
}
ctx.fillStyle = "#fff";
ctx.fillText("Time: ``time`` | ``labels``
\{EM DASH} Solar System demo powered by Ceylon",
10, 10);
}
void loop() {
if (stopped) {
print("Stopped");
return;
}
dynamic {
//schedule the next iteration
requestAnimationFrame(loop);
}
time++;
for (planet in planets) {
planet.orbit();
}
paint();
}
loop();
}
module web_ide_script "1.0.0" {
import ceylon.numeric "1.3.2";
}
"Create the whole solar system."
[Sun, Planet*] createSystem(Integer width, Integer height) {
//Feel free to fiddle with these:
value adjust = height / 250.0;
value dilate = 0.75;
value speed = 2.0;
value moonAdjust = adjust * 10;
function scale(Float f) => f^0.7;
value sol = Sun(width / 2.0, height / 2.0, 35.0 * dilate, "#FFFF44");
value mercurio = Planet("Mercury", sol, 3.0 * dilate, 5.0*speed, "#666565", scale(57.9) * adjust);
value venus = Planet("Venus", sol, 5.0 * dilate, 1.0*speed, "#FFE1C3", scale(108.2) * adjust);
value tierra = Planet("Earth", sol, 6.3 * dilate, 0.5*speed, "#0000FF", scale(149.5) * adjust);
value luna = Planet("Moon", tierra, 2.0 * dilate, 4.0*speed, "#fff", scale(0.384) * moonAdjust);
value marte = Planet("Mars", sol, 4.0 * dilate, 0.3*speed, "#E45117", scale(227.9) * adjust);
value fobos = Planet("Phobos", marte, 0.9 * dilate, 5.0*speed, "#fff", scale(0.00937) * moonAdjust);
value deimos = Planet("Deimos", marte, 0.7 * dilate, 3.0*speed, "#fff", scale(0.0234) * moonAdjust);
value jupiter = Planet("Jupiter", sol, 20.0 * dilate, 0.1*speed, "#FFA347", scale(778.4) * adjust);
value europa = Planet("Europa", jupiter, 2.0 * dilate, 4.0*speed, "#B18829", scale(0.671) * moonAdjust);
value io = Planet("Io", jupiter, 2.0 * dilate, 3.0*speed, "#EA6900", scale(0.42) * moonAdjust);
value ganimedes = Planet("Ganimede", jupiter, 3.0 * dilate, 3.5*speed, "#6C6A68", scale(1.07) * moonAdjust);
value calisto = Planet("Callisto", jupiter, 3.0 * dilate, 2.0*speed, "#726D69", scale(1.88) * moonAdjust);
value saturno = Planet("Saturn", sol, 10.0 * dilate, 0.07*speed, "#FFD4AA", scale(1426.7) * adjust, "#FFDDBB");
value titan = Planet("Titan", saturno, 3.0 * dilate, 1.75*speed, "#FFCA2A", scale(1.22) * adjust + 10.0);
value urano = Planet("Uranus", sol, 8.0 * dilate, 0.05*speed, "#48B5BB", scale(2871.0) * adjust);
value neptuno = Planet("Neptune", sol, 8.0 * dilate, 0.03*speed, "#4471A0", scale(4498.3) * adjust);
value pluton = Planet("Pluto", sol, 2.0 * dilate, 0.01*speed, "#BF6D0A", scale(5906.4) * adjust);
return [
sol,
mercurio, venus,
tierra, luna,
marte, fobos, deimos,
jupiter, europa, io, ganimedes, calisto,
saturno, titan,
urano, neptuno,
pluton
];
}
@ceylonwebide
Copy link
Author

Click here to run this code online

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment