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.core.*
import io.data2viz.viz.TextVAlign
import io.data2viz.viz.TextHAlign
import io.data2viz.viz.FontWeight
import io.data2viz.geom.*
import io.data2viz.color.*
import io.data2viz.shape.*
import io.data2viz.math.*
val width = 700.0
val height = 400.0
val limitH = 100.0
val limitM = 80.0
val limitL = 40.0
fun main() {
// Creating and sizing the VizContainer
val vc = newVizContainer().apply {
size = Size(width, height)
}
vc.chart(values) {
config {
tooltip {
show = false
}
}
val index = discrete( { indexInData } )
val value = quantitative( { domain } )
line(index, value) {
showMarkers = true
strokeColor = constant(Colors.Web.black)
y {
start = -40.0
end = 160.0
}
// add a custom markDecorator inline
markDecorator = { datum, position, drawingZone ->
// call the default decorator
defaultMarkDecorator(datum, position, drawingZone)
// add custom decoration
drawingZone.circle {
x = position.x
y = position.y
radius = 6.0
strokeWidth = 2.0
strokeColor = when {
datum.domain > limitH -> Colors.Web.red
datum.domain > limitM -> Colors.Web.orangered
datum.domain < limitL -> Colors.Web.mediumseagreen
else -> null
}
}
}
// add a custom "highlighted mark" decorator
highlightDecorator = customHiglightDecorator()
}
}
}
private fun customHiglightDecorator(): (Datum<Double>, Point, DrawingZone) -> Unit {
return { datum, position, drawingZone ->
drawingZone.apply {
drawSelector(position)
// add a text if the value is over limits
if (datum.domain > limitH) {
drawAlert(position, "Error!", Colors.Web.red)
} else if (datum.domain > limitM) {
drawAlert(position, "Warning!", Colors.Web.orangered)
} else if (datum.domain < limitL) {
drawAlert(position, "OK", Colors.Web.mediumseagreen)
}
}
}
}
private fun DrawingZone.drawSelector(position: Point) {
// first check the position, if it's placed too far on the right, flip the alert box
val flip = if (position.x < 150.0) -1 else 1
// draw a small red triangle
line {
x1 = position.x - (5.0 * flip)
y1 = position.y
x2 = position.x - (12.0 * flip)
y2 = position.y - (5.0 * flip)
strokeColor = Colors.Web.red
}
line {
x1 = position.x - (12.0 * flip)
y1 = position.y + (5.0 * flip)
x2 = position.x - (12.0 * flip)
y2 = position.y - (5.0 * flip)
strokeColor = Colors.Web.red
}
line {
x1 = position.x - (5.0 * flip)
y1 = position.y
x2 = position.x - (12.0 * flip)
y2 = position.y + (5.0 * flip)
strokeColor = Colors.Web.red
}
}
private fun DrawingZone.drawAlert(position: Point, text: String, color: Color) {
// first check the position, if it's placed too far on the right, flip the alert box
val flip = position.x < 150.0
// Draw a background to make the text more readable
rect {
x = position.x + if (flip) 20.0 else -120.0
y = position.y - 15.0
width = 100.0
height = 30.0
fill = Colors.Web.white.withAlpha(80.pct)
strokeColor = Colors.Web.black.withAlpha(20.pct)
}
// Draw the "warning text"
text {
x = position.x + if (flip) 70.0 else -70.0
y = position.y
vAlign = TextVAlign.MIDDLE
hAlign = TextHAlign.MIDDLE
fontSize = 20.0
textContent = text
fontWeight = FontWeight.BOLD
textColor = color
}
}
val values = listOf(84.0,8.0,24.0,54.0,24.0,67.0,117.0,120.0,17.0,22.0,31.0,33.0,88.0,86.0,81.0,68.0,72.0,54.0,84.0,8.0,24.0,54.0,24.0,67.0,117.0,120.0,17.0,22.0,31.0,33.0,88.0,86.0,81.0,68.0,72.0,54.0)