Skip to content

Instantly share code, notes, and snippets.

@benjaminjackman
Created June 10, 2014 18:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benjaminjackman/e9832bb44c5a59026f69 to your computer and use it in GitHub Desktop.
Save benjaminjackman/e9832bb44c5a59026f69 to your computer and use it in GitHub Desktop.
Example of using three js in scala
package cgta.viz
package learn.threejs
import scala.scalajs.js
import scala.scalajs.js.annotation.JSExport
import cgta.oscala.wraps.tween.{Tween, TWEENJS}
import org.scalajs.dom
@JSExport
object PeriodicTable {
case class Element(symbol: String, name: String, weight: String, col: Int, row: Int)
val rawElements = IVec(
Element("H", "Hydrogen", "1.00794", 1, 1),
Element("He", "Helium", "4.002602", 18, 1),
Element("Li", "Lithium", "6.941", 1, 2),
Element("Be", "Beryllium", "9.012182", 2, 2),
Element("B", "Boron", "10.811", 13, 2),
Element("C", "Carbon", "12.0107", 14, 2),
Element("N", "Nitrogen", "14.0067", 15, 2),
Element("O", "Oxygen", "15.9994", 16, 2),
Element("F", "Fluorine", "18.9984032", 17, 2),
Element("Ne", "Neon", "20.1797", 18, 2),
Element("Na", "Sodium", "22.98976...", 1, 3),
Element("Mg", "Magnesium", "24.305", 2, 3),
Element("Al", "Aluminium", "26.9815386", 13, 3),
Element("Si", "Silicon", "28.0855", 14, 3),
Element("P", "Phosphorus", "30.973762", 15, 3),
Element("S", "Sulfur", "32.065", 16, 3),
Element("Cl", "Chlorine", "35.453", 17, 3),
Element("Ar", "Argon", "39.948", 18, 3),
Element("K", "Potassium", "39.948", 1, 4),
Element("Ca", "Calcium", "40.078", 2, 4),
Element("Sc", "Scandium", "44.955912", 3, 4),
Element("Ti", "Titanium", "47.867", 4, 4),
Element("V", "Vanadium", "50.9415", 5, 4),
Element("Cr", "Chromium", "51.9961", 6, 4),
Element("Mn", "Manganese", "54.938045", 7, 4),
Element("Fe", "Iron", "55.845", 8, 4),
Element("Co", "Cobalt", "58.933195", 9, 4),
Element("Ni", "Nickel", "58.6934", 10, 4),
Element("Cu", "Copper", "63.546", 11, 4),
Element("Zn", "Zinc", "65.38", 12, 4),
Element("Ga", "Gallium", "69.723", 13, 4),
Element("Ge", "Germanium", "72.63", 14, 4),
Element("As", "Arsenic", "74.9216", 15, 4),
Element("Se", "Selenium", "78.96", 16, 4),
Element("Br", "Bromine", "79.904", 17, 4),
Element("Kr", "Krypton", "83.798", 18, 4),
Element("Rb", "Rubidium", "85.4678", 1, 5),
Element("Sr", "Strontium", "87.62", 2, 5),
Element("Y", "Yttrium", "88.90585", 3, 5),
Element("Zr", "Zirconium", "91.224", 4, 5),
Element("Nb", "Niobium", "92.90628", 5, 5),
Element("Mo", "Molybdenum", "95.96", 6, 5),
Element("Tc", "Technetium", "(98)", 7, 5),
Element("Ru", "Ruthenium", "101.07", 8, 5),
Element("Rh", "Rhodium", "102.9055", 9, 5),
Element("Pd", "Palladium", "106.42", 10, 5),
Element("Ag", "Silver", "107.8682", 11, 5),
Element("Cd", "Cadmium", "112.411", 12, 5),
Element("In", "Indium", "114.818", 13, 5),
Element("Sn", "Tin", "118.71", 14, 5),
Element("Sb", "Antimony", "121.76", 15, 5),
Element("Te", "Tellurium", "127.6", 16, 5),
Element("I", "Iodine", "126.90447", 17, 5),
Element("Xe", "Xenon", "131.293", 18, 5),
Element("Cs", "Caesium", "132.9054", 1, 6),
Element("Ba", "Barium", "132.9054", 2, 6),
Element("La", "Lanthanum", "138.90547", 4, 9),
Element("Ce", "Cerium", "140.116", 5, 9),
Element("Pr", "Praseodymium", "140.90765", 6, 9),
Element("Nd", "Neodymium", "144.242", 7, 9),
Element("Pm", "Promethium", "(145)", 8, 9),
Element("Sm", "Samarium", "150.36", 9, 9),
Element("Eu", "Europium", "151.964", 10, 9),
Element("Gd", "Gadolinium", "157.25", 11, 9),
Element("Tb", "Terbium", "158.92535", 12, 9),
Element("Dy", "Dysprosium", "162.5", 13, 9),
Element("Ho", "Holmium", "164.93032", 14, 9),
Element("Er", "Erbium", "167.259", 15, 9),
Element("Tm", "Thulium", "168.93421", 16, 9),
Element("Yb", "Ytterbium", "173.054", 17, 9),
Element("Lu", "Lutetium", "174.9668", 18, 9),
Element("Hf", "Hafnium", "178.49", 4, 6),
Element("Ta", "Tantalum", "180.94788", 5, 6),
Element("W", "Tungsten", "183.84", 6, 6),
Element("Re", "Rhenium", "186.207", 7, 6),
Element("Os", "Osmium", "190.23", 8, 6),
Element("Ir", "Iridium", "192.217", 9, 6),
Element("Pt", "Platinum", "195.084", 10, 6),
Element("Au", "Gold", "196.966569", 11, 6),
Element("Hg", "Mercury", "200.59", 12, 6),
Element("Tl", "Thallium", "204.3833", 13, 6),
Element("Pb", "Lead", "207.2", 14, 6),
Element("Bi", "Bismuth", "208.9804", 15, 6),
Element("Po", "Polonium", "(209)", 16, 6),
Element("At", "Astatine", "(210)", 17, 6),
Element("Rn", "Radon", "(222)", 18, 6),
Element("Fr", "Francium", "(223)", 1, 7),
Element("Ra", "Radium", "(226)", 2, 7),
Element("Ac", "Actinium", "(227)", 4, 10),
Element("Th", "Thorium", "232.03806", 5, 10),
Element("Pa", "Protactinium", "231.0588", 6, 10),
Element("U", "Uranium", "238.02891", 7, 10),
Element("Np", "Neptunium", "(237)", 8, 10),
Element("Pu", "Plutonium", "(244)", 9, 10),
Element("Am", "Americium", "(243)", 10, 10),
Element("Cm", "Curium", "(247)", 11, 10),
Element("Bk", "Berkelium", "(247)", 12, 10),
Element("Cf", "Californium", "(251)", 13, 10),
Element("Es", "Einstenium", "(252)", 14, 10),
Element("Fm", "Fermium", "(257)", 15, 10),
Element("Md", "Mendelevium", "(258)", 16, 10),
Element("No", "Nobelium", "(259)", 17, 10),
Element("Lr", "Lawrencium", "(262)", 18, 10),
Element("Rf", "Rutherfordium", "(267)", 4, 7),
Element("Db", "Dubnium", "(268)", 5, 7),
Element("Sg", "Seaborgium", "(271)", 6, 7),
Element("Bh", "Bohrium", "(272)", 7, 7),
Element("Hs", "Hassium", "(270)", 8, 7),
Element("Mt", "Meitnerium", "(276)", 9, 7),
Element("Ds", "Darmstadium", "(281)", 10, 7),
Element("Rg", "Roentgenium", "(280)", 11, 7),
Element("Cn", "Copernicium", "(285)", 12, 7),
Element("Uut", "Unutrium", "(284)", 13, 7),
Element("Fl", "Flerovium", "(289)", 14, 7),
Element("Uup", "Ununpentium", "(288)", 15, 7),
Element("Lv", "Livermorium", "(293)", 16, 7),
Element("Uus", "Ununseptium", "(294)", 17, 7),
Element("Uuo", "Ununoctium", "(294)", 18, 7))
val elements = rawElements
//++ rawElements ++ rawElements ++ rawElements
case class Targets(
table: js.Array[*] = js.Array(),
sphere: js.Array[*] = js.Array(),
helix: js.Array[*] = js.Array(),
grid: js.Array[*] = js.Array()
)
@JSExport
def start() {
console.log("Periodic Table Start")
var camera: * = null
var scene: * = null
var renderer: * = null
var controls: * = null
var objects = js.Array[*]()
val THREE = global.THREE
val targets = Targets()
//
init()
animate()
//
def init() {
camera = js.Dynamic.newInstance(THREE.PerspectiveCamera)(40, window.innerWidth / window.innerHeight, 1, 10000)
camera.position.z = 3000
scene = js.Dynamic.newInstance(THREE.Scene)()
// table
jfor[Int](0, _ < elements.size, _ + 1) { i: Int =>
var element = document.createElement("div")
element.className = "element"
element.style.backgroundColor = "rgba(0, 127, 127, " + (js.Math.random() * 0.5 + 0.25) + ")"
var number = document.createElement("div")
number.className = "number"
number.textContent = (i + 1).toString
element.appendChild(number)
var symbol = document.createElement("div")
symbol.className = "symbol"
symbol.textContent = elements(i).symbol
element.appendChild(symbol)
var details = document.createElement("div")
details.className = "details"
details.innerHTML = elements(i).name + "<br> " + elements(i).weight
element.appendChild(details)
var obj = js.Dynamic.newInstance(THREE.CSS3DObject)(element)
obj.position.x = js.Math.random() * 4000 - 2000
obj.position.y = js.Math.random() * 4000 - 2000
obj.position.z = js.Math.random() * 4000 - 2000
scene.add(obj)
objects.push(obj)
//
var obj2 = js.Dynamic.newInstance(THREE.Object3D)()
obj2.position.x = (elements(i).col * 140) - 1330
obj2.position.y = -(elements(i).row * 180) + 990
targets.table.push(obj2)
}
// sphere
locally {
val l = objects.length.toDouble
var vector = js.Dynamic.newInstance(THREE.Vector3)()
jfor[Int](0, _ < l, _ + 1) { i: Int =>
var phi = js.Math.acos(-1 + (2 * i) / l)
var theta = js.Math.sqrt(l * js.Math.PI) * phi
var obj = js.Dynamic.newInstance(THREE.Object3D)()
obj.position.x = 800 * js.Math.cos(theta) * js.Math.sin(phi)
obj.position.y = 800 * js.Math.sin(theta) * js.Math.sin(phi)
obj.position.z = 800 * js.Math.cos(phi)
vector.copy(obj.position).multiplyScalar(2)
obj.lookAt(vector)
targets.sphere.push(obj)
}
}
// helix
locally {
var vector = js.Dynamic.newInstance(THREE.Vector3)()
jfor[Int](0, _ < objects.length, _ + 1) { i: Int =>
var phi = i * 0.175 + js.Math.PI
var obj = js.Dynamic.newInstance(THREE.Object3D)()
obj.position.x = 900 * js.Math.sin(phi)
obj.position.y = -(i * 8) + 450
obj.position.z = 900 * js.Math.cos(phi)
vector.x = obj.position.x * 2
vector.y = obj.position.y
vector.z = obj.position.z * 2
obj.lookAt(vector)
targets.helix.push(obj)
}
}
// grid
jfor[Int](0, _ < objects.length, _ + 1) { i: Int =>
var obj = js.Dynamic.newInstance(THREE.Object3D)()
obj.position.x = ((i % 5) * 400) - 800
obj.position.y = (-(js.Math.floor(i / 5) % 5) * 400) + 800
obj.position.z = js.Math.floor(i / 25) * 1000 - 2000
targets.grid.push(obj)
}
//
renderer = js.Dynamic.newInstance(THREE.CSS3DRenderer)()
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.domElement.style.position = "absolute"
document.getElementById("container").appendChild(renderer.domElement.asInstanceOf[dom.Node])
//
controls = js.Dynamic.newInstance(THREE.TrackballControls)(camera, renderer.domElement)
controls.rotateSpeed = 0.5
controls.minDistance = 500
controls.maxDistance = 6000
controls.addEventListener("change", () => render())
document.getElementById("table").addEventListener("click", (x: dom.Event) => transform(targets.table, 2000), false)
document.getElementById("sphere").addEventListener("click", (x: dom.Event) => transform(targets.sphere, 2000), false)
document.getElementById("helix").addEventListener("click", (x: dom.Event) => transform(targets.helix, 2000), false)
document.getElementById("grid").addEventListener("click", (x: dom.Event) => transform(targets.grid, 2000), false)
transform(targets.table, 1000)
//
window.addEventListener("resize", () => onWindowResize(), false)
}
def transform(targets: js.Array[*], durMs: js.Number) {
console.log("transforming to", targets(0))
TWEENJS.removeAll()
var i = 0
while (i < objects.length) {
val obj = objects(i)
val target = targets(i)
new Tween(obj.position)
.to(*(x = target.position.x, y = target.position.y, z = target.position.z), js.Math.random() * durMs + durMs)
.easing(TWEENJS.Easing.Bounce.Out _)
.start()
new Tween(obj.rotation)
.to(*(x = target.rotation.x, y = target.rotation.y, z = target.rotation.z), js.Math.random() * durMs + durMs)
.easing(TWEENJS.Easing.Bounce.Out _)
.start()
i += 1
}
new Tween(window).to(*(), durMs * 2).onUpdate(() => render()).start()
}
def onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
render()
}
def animate() {
window.requestAnimationFrame(() => animate())
TWEENJS.update()
controls.update()
}
def render() {
renderer.render(scene, camera)
}
}
}
package cgta.oscala
package wraps.tween
import scala.scalajs.js
import scala.scalajs.js.annotation.JSName
@JSName("TWEEN")
object TWEENJS extends js.Object {
// Type definitions for tween.js r12
// Project: https://github.com/sole/tween.js/
// Definitions by: sunetos <https://github.com/sunetos>, jzarnikov <https://github.com/jzarnikov>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
val REVISION: js.String = ???
def getAll(): js.Array[Tween] = ???
def removeAll(): Unit = ???
def add(tween: Tween): Unit = ???
def remove(tween: Tween): Unit = ???
def update(time: js.Number = ???): js.Boolean = ???
val Easing : Tween.Easing = ???
val Interpolation: Tween.Interpolation = ???
}
@JSName("TWEEN.Tween")
class Tween(obj: js.Any = ???) extends js.Object {
def to(properties: js.Any, duration: js.Number): Tween = ???
def start(time: js.Number = ???): Tween = ???
def stop(): Tween = ???
def delay(amount: js.Number): Tween = ???
def easing(easing: js.Function1[js.Number, js.Number]): Tween = ???
def interpolation(interpolation: js.Function2[js.Array[js.Number], js.Number, js.Number]): Tween = ???
def chain(tweens: Tween*): Tween = ???
def onStart(callback: js.Function1[js.Any, Unit]): Tween = ???
def onUpdate(callback: js.Function1[js.Any, Unit]): Tween = ???
def onComplete(callback: js.Function1[js.Any, Unit]): Tween = ???
def onStart(callback: js.Function0[Unit]): Tween = ???
def onUpdate(callback: js.Function0[Unit]): Tween = ???
def onComplete(callback: js.Function0[Unit]): Tween = ???
def update(time: js.Number): js.Boolean = ???
def repeat(times: js.Number): Tween = ???
def yoyo(enable: js.Boolean): Tween = ???
}
object Tween {
trait InOutEasingFns extends js.Object {
def In(x: js.Number): js.Number = ???
def Out(x: js.Number): js.Number = ???
def InOut(x: js.Number): js.Number = ???
}
trait LinearEasingFns extends js.Object {
def None(x: js.Number): js.Number
}
trait Easing extends js.Object {
val Linear : LinearEasingFns = ???
val Quadratic : InOutEasingFns = ???
val Cubic : InOutEasingFns = ???
val Quartic : InOutEasingFns = ???
val Quintic : InOutEasingFns = ???
val Sinusoidal : InOutEasingFns = ???
val Exponential: InOutEasingFns = ???
val Circular : InOutEasingFns = ???
val Elastic : InOutEasingFns = ???
val Back : InOutEasingFns = ???
val Bounce : InOutEasingFns = ???
}
trait InterpolationUtils extends js.Object {
def Linear(p0: js.Number, p1: js.Number, t: js.Number): js.Number = ???
def Bernstein(n: js.Number, i: js.Number): js.Number = ???
def Factorial(n: js.Number): js.Number = ???
}
trait Interpolation extends js.Object {
def Linear(v: js.Array[js.Number], k: js.Number): js.Number = ???
def Bezier(v: js.Array[js.Number], k: js.Number): js.Number = ???
def CatmullRom(v: js.Array[js.Number], k: js.Number): js.Number = ???
val Utils: InterpolationUtils = ???
}
}
package cgta.oscala
package sjs
import scala.scalajs.js
import cgta.oscala.sjs.lang.JsConsole
object OScalaSjsExports extends OScalaSjsExports
trait OScalaSjsExports {
val global = js.Dynamic.global
val console = global.console.asInstanceOf[JsConsole]
val JSON = global.JSON
val undefined = global.undefined
val window = global.window
val document = org.scalajs.dom.document
def newObject = js.Object().asInstanceOf[js.Dynamic]
// def new_*(clazz: js.Dynamic)(): js.Dynamic = js.Dynamic.newInstance(clazz)()
// def new_*(clazz: js.Dynamic)(a0: js.Any): js.Dynamic = js.Dynamic.newInstance(clazz)(a0)
// def new_*(clazz: js.Dynamic)(a0: js.Any, a1: js.Any): js.Dynamic = js.Dynamic.newInstance(clazz)(a0, a1)
// def new_*(clazz: js.Dynamic)(a0: js.Any, a1: js.Any, a2: js.Any): js.Dynamic = js.Dynamic.newInstance(clazz)(a0, a1, a2)
// def new_*(clazz: js.Dynamic)(args: js.Any*): js.Dynamic = js.Dynamic.newInstance(clazz)(args: _*)
// def new_*(clazz: js.Dynamic)(args: js.Any*): js.Dynamic = js.Dynamic.newInstance(clazz)(args: _*)
val * = js.Dynamic.literal
type * = js.Dynamic
type ** = js.Object with js.Dynamic
def log(args: js.Any*) = console.log(args: _*)
def jfor[A](init: A, p: A => Boolean, inc: A => A)(f: A => Unit) {
var x = init
while (p(x)) {
f(x)
x = inc(x)
}
}
// implicit object QueueExecutionContext extends ExecutionContext {
//
// def execute(runnable: Runnable) = {
// val lambda: js.Function = () =>
// try {runnable.run()} catch {case t: Throwable => reportFailure(t)}
// js.Dynamic.global.setTimeout(lambda, 0)
// }
//
// def reportFailure(t: Throwable) =
// Console.err.println("Failure in async execution: " + t)
//
// }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment