import io.data2viz.chord.Chord
import io.data2viz.chord.ChordGroup
import io.data2viz.chord.ChordLayout
import io.data2viz.chord.Chords
import io.data2viz.color.*
import io.data2viz.geom.Path
import io.data2viz.geom.Point
import io.data2viz.geom.Size
import io.data2viz.math.Percent
import io.data2viz.math.pct
import io.data2viz.shape.arcBuilder
import io.data2viz.viz.*
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin
fun main() {
chordViz().bindRendererOnNewCanvas()
}
data class Movie(val name: String, val avengers: List<Avenger>)
data class Avenger(val name: String)
val blackWidow = Avenger("Black Widow")
val captainAmerica = Avenger("Captain America")
val theHulk = Avenger("the Hulk")
val ironMan = Avenger("Iron Man")
val thor = Avenger("Thor")
val hawkeye = Avenger("hawkeye")
val movies = listOf(
Movie("Avengers", listOf(ironMan, captainAmerica, theHulk, thor, hawkeye, blackWidow)),
Movie("Avengers, L'ère d'Ultron", listOf(ironMan, captainAmerica, theHulk, thor, hawkeye, blackWidow)),
Movie("Avengers, Infinity War", listOf(ironMan, captainAmerica, theHulk, hawkeye, blackWidow)),
Movie("Captain America, First Avenger", listOf(captainAmerica)),
Movie("Captain America, Le Soldat de l'hiver", listOf(captainAmerica, blackWidow)),
Movie("Captain America, Civil War", listOf(captainAmerica, ironMan, hawkeye, blackWidow)),
Movie("Iron Man 1", listOf(ironMan)),
Movie("Iron Man 2", listOf(ironMan, blackWidow)),
Movie("Iron Man 3", listOf(ironMan, theHulk)),
Movie("Thor", listOf(thor, hawkeye)),
Movie("Thor, le monde des ténèbres", listOf(thor, captainAmerica)),
Movie("Thor, Ragnarok", listOf(thor, theHulk))
)
val avengers = listOf(blackWidow, captainAmerica, hawkeye, theHulk, ironMan, thor)
val colors = listOf(0x301E1E, 0x083E77, 0x342350, 0x567235, 0x8B161C, 0xDF7C00).map { Colors.rgb(it) }
val chordSize = Size(720.0, 720.0)
val outer = minOf(chordSize.width, chordSize.height) * 0.5 - 40.0
val inner = outer - 30
val chord = ChordLayout<Avenger>().apply {
padAngle = .15
}
fun collaborations(avengers: List<Avenger>) = movies.filter { it.avengers.containsAll(avengers) }.size.toDouble()
val avengersChords: Chords = chord.chord(avengers) { a, b -> if (a == b) .0 else collaborations(listOf(a, b)) }
val avengersArcBuilder = arcBuilder<ChordGroup> {
innerRadius = { inner + 3 }
outerRadius = { outer }
startAngle = { it.startAngle }
endAngle = { it.endAngle }
}
val ribbon: (Chord, Path) -> Unit = io.data2viz.chord.ribbon(inner)
fun chordViz(): Viz = viz {
size = chordSize
group {
//todo create a center function
transform { translate(width / 2, height / 2) }
//Drawing external groups representing avengers
avengersChords.groups.forEachIndexed { index, it ->
path {
fill = colors[index]
avengersArcBuilder.buildArcForDatum(it, this)
stroke = null
}
}
//drawing ribbons
avengersChords.chords.forEach { chord ->
path {
fill = chord.toGradient(60.pct)
stroke = null
ribbon(chord, this)
}
}
}
}
//Todo Move in API
fun Chord.toGradient(alpha:Percent) = Colors.Gradient.linear(
Point(
inner * cos((source.endAngle - source.startAngle) / 2 + source.startAngle - PI / 2),
inner * sin((source.endAngle - source.startAngle) / 2 + source.startAngle - PI / 2)
),
Point(
inner * cos((target.endAngle - target.startAngle) / 2 + target.startAngle - PI / 2),
inner * sin((target.endAngle - target.startAngle) / 2 + target.startAngle - PI / 2)
)
).withColor(colors[source.index].withAlpha(alpha))
.andColor(colors[target.index].withAlpha(alpha))