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)