diff --git a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart10.kt b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart10.kt index 6a2412662..9c2562bdd 100644 --- a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart10.kt +++ b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart10.kt @@ -73,7 +73,7 @@ private fun ComposeChart10(modelProducer: CartesianChartModelProducer, modifier: guideline = null, itemPlacer = remember { - HorizontalAxis.ItemPlacer.aligned(spacing = 3, addExtremeLabelPadding = true) + HorizontalAxis.ItemPlacer.aligned(spacing = { 3 }, addExtremeLabelPadding = true) }, ), marker = marker, diff --git a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart2.kt b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart2.kt index e6fd28b5a..0e256813e 100644 --- a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart2.kt +++ b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart2.kt @@ -99,7 +99,7 @@ private fun ComposeChart2(modelProducer: CartesianChartModelProducer, modifier: valueFormatter = bottomAxisValueFormatter, itemPlacer = remember { - HorizontalAxis.ItemPlacer.aligned(spacing = 3, addExtremeLabelPadding = true) + HorizontalAxis.ItemPlacer.aligned(spacing = { 3 }, addExtremeLabelPadding = true) }, ), marker = rememberMarker(), diff --git a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart9.kt b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart9.kt index 59d094be0..1f86560b2 100644 --- a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart9.kt +++ b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/charts/Chart9.kt @@ -172,7 +172,7 @@ private fun ComposeChart9(modelProducer: CartesianChartModelProducer, modifier: guideline = null, itemPlacer = remember { - HorizontalAxis.ItemPlacer.aligned(spacing = 3, addExtremeLabelPadding = true) + HorizontalAxis.ItemPlacer.aligned(spacing = { 3 }, addExtremeLabelPadding = true) }, ), marker = marker, diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxis.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxis.kt index d0c2f8ad5..6b96ca463 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxis.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxis.kt @@ -16,7 +16,6 @@ package com.patrykandpatrick.vico.core.cartesian.axis -import androidx.annotation.IntRange import androidx.annotation.RestrictTo import com.patrykandpatrick.vico.core.cartesian.CartesianDrawingContext import com.patrykandpatrick.vico.core.cartesian.CartesianMeasuringContext @@ -31,6 +30,7 @@ import com.patrykandpatrick.vico.core.common.Insets import com.patrykandpatrick.vico.core.common.VerticalPosition import com.patrykandpatrick.vico.core.common.component.LineComponent import com.patrykandpatrick.vico.core.common.component.TextComponent +import com.patrykandpatrick.vico.core.common.data.ExtraStore import com.patrykandpatrick.vico.core.common.doubled import com.patrykandpatrick.vico.core.common.getStart import com.patrykandpatrick.vico.core.common.half @@ -597,15 +597,15 @@ protected constructor( public companion object { /** * Adds a label, tick, and guideline for each _x_ value given by [CartesianChartRanges.minX] + - * (k × [spacing] + [offset]) × [CartesianChartRanges.xStep], where _k_ ∈ ℕ, with these + * (_k_ × spacing + offset) × [CartesianChartRanges.xStep], where _k_ ∈ ℕ, with these * components being horizontally centered relative to one another. [shiftExtremeLines] is used * as the return value of [ItemPlacer.getShiftExtremeLines]. [addExtremeLabelPadding] * specifies whether [CartesianLayer] padding should be added for the first and last labels, * ensuring their visibility. */ public fun aligned( - @IntRange(from = 1) spacing: Int = 1, - @IntRange(from = 0) offset: Int = 0, + spacing: (ExtraStore) -> Int = { 1 }, + offset: (ExtraStore) -> Int = { 0 }, shiftExtremeLines: Boolean = true, addExtremeLabelPadding: Boolean = true, ): ItemPlacer = @@ -615,7 +615,7 @@ protected constructor( * Adds a label for each major _x_ value, and adds ticks between the labels and for * [CartesianChartRanges.minX] − [CartesianChartRanges.xStep] ÷ 2 and * [CartesianChartRanges.maxX] + [CartesianChartRanges.xStep] ÷ 2. (Major _x_ values are given - * by [CartesianChartRanges.minX] + k × [CartesianChartRanges.xStep], where _k_ ∈ ℕ.) + * by [CartesianChartRanges.minX] + _k_ × [CartesianChartRanges.xStep], where _k_ ∈ ℕ.) * [shiftExtremeLines] is used as the return value of [ItemPlacer.getShiftExtremeLines]. */ public fun segmented(shiftExtremeLines: Boolean = true): ItemPlacer = diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxisItemPlacers.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxisItemPlacers.kt index 988c951f4..661c4edfb 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxisItemPlacers.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/HorizontalAxisItemPlacers.kt @@ -20,6 +20,7 @@ import com.patrykandpatrick.vico.core.cartesian.CartesianDrawingContext import com.patrykandpatrick.vico.core.cartesian.CartesianMeasuringContext import com.patrykandpatrick.vico.core.cartesian.HorizontalDimensions import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartRanges +import com.patrykandpatrick.vico.core.common.data.ExtraStore import com.patrykandpatrick.vico.core.common.half import com.patrykandpatrick.vico.core.common.roundedToNearest import kotlin.math.ceil @@ -77,22 +78,31 @@ internal abstract class BaseHorizontalAxisItemPlacer(private val shiftExtremeLin } internal class AlignedHorizontalAxisItemPlacer( - private val spacing: Int, - private val offset: Int, + private val spacing: (ExtraStore) -> Int, + private val offset: (ExtraStore) -> Int, private val shiftExtremeLines: Boolean, private val addExtremeLabelPadding: Boolean, ) : BaseHorizontalAxisItemPlacer(shiftExtremeLines) { - init { - require(spacing > 0) { "`spacing` must be positive." } - require(offset >= 0) { "`offset` must be nonnegative." } - } + private fun CartesianMeasuringContext.getSpacingOrThrow() = + spacing(model.extraStore).also { require(it > 0) { "`spacing` must return a positive value." } } + + private fun CartesianMeasuringContext.getOffsetOrThrow() = + offset(model.extraStore).also { + require(it >= 0) { "`offset` must return a nonnegative value." } + } override fun getFirstLabelValue(context: CartesianMeasuringContext, maxLabelWidth: Float) = - if (addExtremeLabelPadding) context.ranges.minX + offset * context.ranges.xStep else null + context.run { + if (addExtremeLabelPadding) ranges.minX + getOffsetOrThrow() * ranges.xStep else null + } override fun getLastLabelValue(context: CartesianMeasuringContext, maxLabelWidth: Float) = if (addExtremeLabelPadding) { - with(context.ranges) { maxX - (xLength - xStep * offset) % (xStep * spacing) } + context.run { + ranges.maxX - + (ranges.xLength - ranges.xStep * getOffsetOrThrow()) % + (ranges.xStep * getSpacingOrThrow()) + } } else { null } @@ -103,18 +113,21 @@ internal class AlignedHorizontalAxisItemPlacer( fullXRange: ClosedFloatingPointRange, maxLabelWidth: Float, ) = - context.getLabelValues( - visibleXRange = visibleXRange, - fullXRange = fullXRange, - offset = offset, - spacing = - spacing * - if (addExtremeLabelPadding && maxLabelWidth != 0f) { - ceil(maxLabelWidth / (context.horizontalDimensions.xSpacing * spacing)).toInt() - } else { - 1 - }, - ) + context.run { + val spacing = getSpacingOrThrow() + getLabelValues( + visibleXRange = visibleXRange, + fullXRange = fullXRange, + offset = getOffsetOrThrow(), + spacing = + spacing * + if (addExtremeLabelPadding && maxLabelWidth != 0f) { + ceil(maxLabelWidth / (context.horizontalDimensions.xSpacing * spacing)).toInt() + } else { + 1 + }, + ) + } override fun getWidthMeasurementLabelValues( context: CartesianMeasuringContext, diff --git a/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/theme/ThemeHandler.kt b/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/theme/ThemeHandler.kt index c5b0f1202..e7ecbf236 100644 --- a/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/theme/ThemeHandler.kt +++ b/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/theme/ThemeHandler.kt @@ -279,11 +279,13 @@ internal class ThemeHandler(private val context: Context, attrs: AttributeSet?) private fun TypedArray.getHorizontalAxisItemPlacer(): HorizontalAxis.ItemPlacer { val shiftExtremeLines = getBoolean(R.styleable.AxisStyle_shiftExtremeHorizontalAxisLines, true) + val spacing = getInteger(R.styleable.AxisStyle_horizontalAxisLabelSpacing, 1) + val offset = getInteger(R.styleable.AxisStyle_horizontalAxisLabelOffset, 0) return when (getInteger(R.styleable.AxisStyle_horizontalAxisItemPlacer, 0)) { 0 -> HorizontalAxis.ItemPlacer.aligned( - getInteger(R.styleable.AxisStyle_horizontalAxisLabelSpacing, 1), - getInteger(R.styleable.AxisStyle_horizontalAxisLabelOffset, 0), + { spacing }, + { offset }, shiftExtremeLines, getBoolean(R.styleable.AxisStyle_addExtremeHorizontalAxisLabelPadding, true), )