All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tri.covid19.coda.utils.FxChartUtils.kt Maven / Gradle / Ivy

package tri.covid19.coda.utils

import javafx.scene.chart.LineChart
import javafx.scene.chart.NumberAxis
import javafx.scene.chart.XYChart
import javafx.util.StringConverter
import tornadofx.*
import tri.util.monthDay
import java.time.LocalDate
import kotlin.math.floor
import kotlin.math.log10
import kotlin.math.pow

/** Set chart series as list of [ChartDataSeries]. */
var LineChart.dataSeries: List
    get() = listOf()
    set(value) {
        data.clear()
        value.forEach {
            this.series(it.id, it.points.map { xy(it.first, it.second) }.asObservable())
        }
    }

/** Adds a context menu to chart with maximize/restore options. */
internal fun LineChart<*, *>.chartContextMenu() = contextmenu {
    item("Maximize").action { maximizeInParent() }
    item("Restore").action { restoreInParent() }
}

internal fun LineChart<*, *>.maximizeInParent() {
    val p = this.parent
    p.childrenUnmodifiable.filter { it != this && it is LineChart<*, *> }
            .forEach { it.isManaged = false;
/*-
 * #%L
 * coda-app
 * --
 * Copyright (C) 2020 - 2022 Elisha Peterson
 * --
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
 it.isVisible = false }
}

internal fun LineChart<*, *>.restoreInParent() {
    val p = this.parent
    p.childrenUnmodifiable.forEach { it.isManaged = true; it.isVisible = true }
}

/** Shortcut for chart data point. */
fun xy(x: Number, y: Number) = XYChart.Data(x, y)

/** Set chart line width for all series. */
var LineChart<*, *>.lineWidth: String
    get() = "1px"
    set(value) = data.forEach {
        it.nodeProperty().get().style = "-fx-stroke-width: $value"
    }

fun lineChartWidthForCount(count: Int) = when {
    count <= 5 -> "2px"
    count <= 10 -> "1.5px"
    count <= 20 -> "1px"
    else -> "0.8px"
}

/** For labeling axis by dates. */
fun axisLabeler(day0: LocalDate) = object : StringConverter() {
    override fun toString(i: Number) = day0.plusDays(i.toLong()).monthDay
    override fun fromString(s: String): Number = TODO()
}

private fun NumberAxis.limitMaxTo(maxOther: Double?, max: Double?, multiplier: Double) {
    when {
        max == null || maxOther == null -> isAutoRanging = true
        maxOther >= max*multiplier -> {
            isAutoRanging = false
            lowerBound = 0.0
            upperBound = (max*multiplier).logRound()
        }
        else -> isAutoRanging = true
    }
}

private fun Double.logRound(): Double {
    val base = 10.0.pow(floor(log10(this)))
    return when {
        base >= this -> base
        2*base >= this -> 2*base
        else -> 5*base
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy