import io.data2viz.color.*
import io.data2viz.geom.*
import io.data2viz.math.*
import io.data2viz.viz.*
import kotlin.math.sin
import kotlin.math.cos
import kotlin.math.abs
val numBalls = 30
val ballSize = 8.0
val spacing = 60.0
val vizWidth = 600.0
val vizHeight = 600.0
val speed = 0.5
lateinit var balls: List<Triple<LineNode, CircleNode, CircleNode>>
fun main() {
val yOffset = - (numBalls * ballSize)
viz {
size = size(vizWidth, vizHeight)
group {
transform {
translate(vizWidth / 2.0, vizHeight / 2.0)
}
balls = (0 .. numBalls).map { index ->
val h = (index * ballSize * 2) + yOffset
Triple(
line {
y1 = h
y2 = h
strokeColor = Colors.Web.grey
},
circle {
y = h
},
circle {
y = h
}
)
}
var frame = .0
animation {
frame += speed
transform {
translate(300.0, 300.0)
rotate(frame / 50.0)
}
balls.forEachIndexed { index, pair ->
val sinus = sin(PI * ((index+frame) / numBalls.toDouble()))
val cosinus = cos(PI * ((index+frame) / numBalls.toDouble()))
val w = spacing * sinus
pair.first.x1 = w
pair.first.x2 = -w
// swap circles so the smallest one is always behind the big one
if (cosinus <= .0) {
pair.second.fill = Colors.hsl((120 + frame + 6*index).deg, 100.pct, (40 + (20 * cosinus)).pct)
pair.second.x = w
pair.second.radius = 3.0 + 5.0 * (cosinus + 1.2)
pair.third.fill = Colors.hsl((frame + 6*index).deg, 100.pct, (40 + (20 * -cosinus)).pct)
pair.third.x = -w
pair.third.radius = 3.0 + 5.0 * (-cosinus + 1.2)
} else {
pair.third.fill = Colors.hsl((120 + frame + 6*index).deg, 100.pct, (40 + (20 * cosinus)).pct)
pair.third.x = w
pair.third.radius = 3.0 + 5.0 * (cosinus + 1.2)
pair.second.fill = Colors.hsl((frame + 6*index).deg, 100.pct, (40 + (20 * -cosinus)).pct)
pair.second.x = -w
pair.second.radius = 3.0 + 5.0 * (-cosinus + 1.2)
}
}
}
}
}.bindRendererOnNewCanvas()
}