Skip to content

Instantly share code, notes, and snippets.

@ceylonwebide
Last active August 13, 2017 15:09
Show Gist options
  • Select an option

  • Save ceylonwebide/bd41b47f325b6d32514a to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown
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