import io.data2viz.charts.*
import io.data2viz.charts.core.Padding
import io.data2viz.charts.core.*
import io.data2viz.charts.dimension.*
import io.data2viz.charts.chart.*
import io.data2viz.charts.chart.mark.*
import io.data2viz.charts.viz.*
import io.data2viz.charts.layout.*
import io.data2viz.charts.config.configs.*
import io.data2viz.math.*
import io.data2viz.color.*
import io.data2viz.geom.*
import io.data2viz.shape.Symbols
import io.data2viz.dsv.Dsv
import org.w3c.fetch.Response
import org.w3c.dom.events.EventListener
import org.w3c.dom.events.Event
import org.w3c.dom.events.KeyboardEvent
import kotlinx.browser.document
import kotlinx.browser.window
import kotlin.js.Promise
import kotlin.math.*
import kotlinx.datetime.Instant
val width = 600.0
val height = 400.0
// The dataset holds 2016 & 2017
private val year = 2017
// The "Weather" class
data class Weather(
val city: String,
val year: Int,
val month: Int,
val highTemp: Double,
val avgTemp: Double,
val lowTemp: Double,
val precip: Double
)
// This function transform a CSV line to a "Weather" instance
private fun parseWeather(row: List<String>) = Weather(
row[0],
row[1].toInt(),
row[2].toInt(),
row[3].toDouble(),
row[4].toDouble(),
row[5].toDouble(),
row[6].toDouble()
)
// Just use a simple list of months label for the X axis
private val months = listOf("Jan.", "Feb.", "Mar.", "Apr.", "May", "Jun.", "Jul.", "Aug.", "Sep.", "Oct.", "Nov.", "Dec.")
lateinit var chart: Chart<Weather>
lateinit var results: List<Weather>
private var selectedIndex: Int = 0
private var selectedSeries: Int = 0
fun main() {
// Creating and sizing the VizContainer
val vc = newVizContainer().apply {
size = Size(width, height)
}
// source file: https://docs.google.com/spreadsheets/d/1Rwa_frxeBqPad4bqxfm8sTxL8FRDSFODnreSWBhXvwg/edit?usp=sharing
// original taken from https://vincentarelbundock.github.io/Rdatasets/
val request: Promise<Response> =
window.fetch("https://docs.google.com/spreadsheets/d/e/2PACX-1vTX4QuCNyDvUoAwk6Jl6UJ4r336A87VIKQ5BVyEgowXG_raXdFBMvmUhmz1LLc07GavyC9J6pZ4YHqJ/pub?gid=650761999&single=true&output=csv")
request.then {
it.text().then {
results = Dsv()
.parseRows(it)
.drop(1)
.map { parseWeather(it) }
.filter { it.year == year }
chart = vc.chart(results) {
title = "Arrow-selection: focus (click) on chart and use arrows"
config {
cursor {
show = true
}
legend {
show = LegendVisibility.Show
}
events {
selectionMode = SelectionMode.None
highlightMode = HighlightMode.None
}
}
series = discrete( { domain.city } )
val monthDim = discrete( { domain.month } ) {
formatter = { "${months[this - 1]} "}
}
val tempDim = quantitative( { domain.avgTemp } ) {
name = "Average temperature for the month"
formatter = { "$this°F" }
}
area(monthDim, tempDim) {
stacking = Stacking.Standard
curve = MarkCurves.Curved
size = constant(30.0)
marker = constant(Symbols.Circle)
showMarkers = true
}
}
}
}
val keyListener = object : EventListener {
override fun handleEvent(event: Event) {
(event as KeyboardEvent).apply {
event.preventDefault()
when (event.code) {
"ArrowLeft" -> selectedIndex = max(0, selectedIndex-1)
"ArrowRight" -> selectedIndex = min(11, selectedIndex+1)
"ArrowDown" -> selectedSeries = max(0, selectedSeries-1)
"ArrowUp" -> selectedSeries = min(4, selectedSeries+1)
else -> return
}
chart.select(listOf(results[(selectedSeries * 12) + selectedIndex]))
}
}
}
document.body?.addEventListener("keydown", keyListener)
}