diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/DeviceMetrics.kt b/app/src/main/java/com/geeksville/mesh/ui/components/DeviceMetrics.kt index b4ab0e8b5..500053918 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/DeviceMetrics.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/DeviceMetrics.kt @@ -66,7 +66,7 @@ import com.geeksville.mesh.ui.components.CommonCharts.MS_PER_SEC import com.geeksville.mesh.ui.components.CommonCharts.DATE_TIME_FORMAT import com.geeksville.mesh.ui.theme.Orange import com.geeksville.mesh.util.GraphUtil.plotPoint -import java.util.concurrent.TimeUnit +import com.geeksville.mesh.util.GraphUtil.createPath private val DEVICE_METRICS_COLORS = listOf(Color.Green, Color.Magenta, Color.Cyan) private const val MAX_PERCENT_VALUE = 100f @@ -224,45 +224,25 @@ private fun DeviceMetricsChart( ) } - // TODO this works to draw lines only according to it's time - // Can this be made into a function that could be reused for other graphs??? + /* Battery Line */ var index = 0 - var timeBreak = false while (index < telemetries.size) { - val testPath = Path().apply { - while(index < telemetries.size) { - val telemetry = telemetries[index] - val nextTelemetry = telemetries.getOrNull(index + 1) ?: telemetries.last() - - /* Check to see if we have a significant time break between telemetries. */ - if (nextTelemetry.time - telemetry.time > TimeUnit.HOURS.toSeconds(2)) { // TODO constant - timeBreak = true - index++ - break - } - - val x1Ratio = (telemetry.time - oldest.time).toFloat() / timeDiff - val x1 = x1Ratio * width - val y1Ratio = telemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE - val y1 = height - (y1Ratio * height) - - val x2Ratio = (nextTelemetry.time - oldest.time).toFloat() / timeDiff - val x2 = x2Ratio * width - val y2Ratio = nextTelemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE - val y2 = height - (y2Ratio * height) - - if (timeBreak || index == 0) { - timeBreak = false - moveTo(x1, y1) - } - - quadraticTo(x1, y1, (x1 + x2) / 2f, (y1 + y2) / 2f) - - index++ - } + val path = Path() + index = createPath( + telemetries = telemetries, + index = index, + path = path, + oldestTime = oldest.time, + timeRange = timeDiff, + width = width + ) { i -> + val telemetry = telemetries.getOrNull(i) ?: telemetries.last() + val ratio = telemetry.deviceMetrics.batteryLevel / MAX_PERCENT_VALUE + val y = height - (ratio * height) + return@createPath y } drawPath( - path = testPath, + path = path, color = DEVICE_METRICS_COLORS[Device.BATTERY.ordinal], style = Stroke( width = dataPointRadius, diff --git a/app/src/main/java/com/geeksville/mesh/util/GraphUtil.kt b/app/src/main/java/com/geeksville/mesh/util/GraphUtil.kt index 5390576f1..04e3151cb 100644 --- a/app/src/main/java/com/geeksville/mesh/util/GraphUtil.kt +++ b/app/src/main/java/com/geeksville/mesh/util/GraphUtil.kt @@ -1,8 +1,13 @@ package com.geeksville.mesh.util +import androidx.compose.ui.graphics.Path import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.DrawContext +import com.geeksville.mesh.TelemetryProtos.Telemetry +import java.util.concurrent.TimeUnit + +private const val TIME_SEPARATION_THRESHOLD = 2L object GraphUtil { @@ -28,5 +33,56 @@ object GraphUtil { ) } - // TODO implement drawing line + /** + * Creates a [Path] that could be used to draw a line from the `index` to the end of `telemetries` + * or the last point before a time separation between [Telemetry]s. + * + * @param telemetries data used to create the [Path] + * @param index current place in the [List] + * @param path [Path] that will be used to draw + * @param timeRange The time range for the data set + * @param width of the [DrawContext] + * @param calculateY (`index`) -> `y` coordinate + */ + fun createPath( + telemetries: List, + index: Int, + path: Path, + oldestTime: Int, + timeRange: Int, + width: Float, + calculateY: (Int) -> Float + ): Int { + var i = index + var isNewLine = true + with (path) { + while (i < telemetries.size) { + val telemetry = telemetries[i] + val nextTelemetry = telemetries.getOrNull(i + 1) ?: telemetries.last() + + /* Check to see if we have a significant time break between telemetries. */ + if (nextTelemetry.time - telemetry.time > TimeUnit.HOURS.toSeconds(TIME_SEPARATION_THRESHOLD)) { + i++ + break + } + + val x1Ratio = (telemetry.time - oldestTime).toFloat() / timeRange + val x1 = x1Ratio * width + val y1 = calculateY(i) + + val x2Ratio = (nextTelemetry.time - oldestTime).toFloat() / timeRange + val x2 = x2Ratio * width + val y2 = calculateY(i + 1) + + if (isNewLine || i == 0) { + isNewLine = false + moveTo(x1, y1) + } + + quadraticTo(x1, y1, (x1 + x2) / 2f, (y1 + y2) / 2f) + i++ + } + } + return i + } }