diff --git a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/Marker.kt b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/Marker.kt index 84dad1482..22061d7d9 100644 --- a/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/Marker.kt +++ b/sample/src/main/java/com/patrykandpatrick/vico/sample/showcase/Marker.kt @@ -97,17 +97,25 @@ internal fun rememberMarker( }, guideline = guideline, ) { - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ) { with(context) { - super.getInsets(context, outInsets, horizontalDimensions) val baseShadowInsetDp = CLIPPING_FREE_SHADOW_RADIUS_MULTIPLIER * LABEL_BACKGROUND_SHADOW_RADIUS_DP - outInsets.top += (baseShadowInsetDp - LABEL_BACKGROUND_SHADOW_DY_DP).pixels - outInsets.bottom += (baseShadowInsetDp + LABEL_BACKGROUND_SHADOW_DY_DP).pixels + var topInset = (baseShadowInsetDp - LABEL_BACKGROUND_SHADOW_DY_DP).pixels + var bottomInset = (baseShadowInsetDp + LABEL_BACKGROUND_SHADOW_DY_DP).pixels + when (labelPosition) { + LabelPosition.Top, + LabelPosition.AbovePoint -> + topInset += label.getHeight(context) + label.tickSizeDp.pixels + LabelPosition.Bottom -> + bottomInset += label.getHeight(context) + label.tickSizeDp.pixels + LabelPosition.AroundPoint -> Unit + } + insets.ensureValuesAtLeast(top = topInset, bottom = bottomInset) } } } diff --git a/vico/compose/src/main/java/com/patrykandpatrick/vico/compose/cartesian/CartesianChartHost.kt b/vico/compose/src/main/java/com/patrykandpatrick/vico/compose/cartesian/CartesianChartHost.kt index 723a85601..f389b157f 100644 --- a/vico/compose/src/main/java/com/patrykandpatrick/vico/compose/cartesian/CartesianChartHost.kt +++ b/vico/compose/src/main/java/com/patrykandpatrick/vico/compose/cartesian/CartesianChartHost.kt @@ -200,13 +200,13 @@ internal fun CartesianChartHostImpl( horizontalLayout: HorizontalLayout, chartValues: ChartValues, ) { - val bounds = remember { RectF() } + val canvasBounds = remember { RectF() } val markerTouchPoint = remember { mutableStateOf(null) } val measureContext = rememberCartesianMeasureContext( scrollState.scrollEnabled, zoomState.zoomEnabled, - bounds, + canvasBounds, horizontalLayout, with(LocalContext.current) { ::spToPx }, chartValues, @@ -251,10 +251,10 @@ internal fun CartesianChartHostImpl( }, ) ) { - bounds.set(left = 0, top = 0, right = size.width, bottom = size.height) + canvasBounds.set(left = 0, top = 0, right = size.width, bottom = size.height) horizontalDimensions.clear() - chart.prepare(measureContext, model, horizontalDimensions, bounds, marker) + chart.prepare(measureContext, model, horizontalDimensions, canvasBounds, marker) if (chart.bounds.isEmpty) return@Canvas diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/CartesianChart.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/CartesianChart.kt index bb3adc037..dfb4ad561 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/CartesianChart.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/CartesianChart.kt @@ -34,6 +34,7 @@ import com.patrykandpatrick.vico.core.common.BoundsAware import com.patrykandpatrick.vico.core.common.Legend import com.patrykandpatrick.vico.core.common.data.MutableExtraStore import com.patrykandpatrick.vico.core.common.inClip +import com.patrykandpatrick.vico.core.common.orZero import com.patrykandpatrick.vico.core.common.set import com.patrykandpatrick.vico.core.common.setAll import java.util.SortedMap @@ -52,9 +53,8 @@ public open class CartesianChart( ) : BoundsAware, ChartInsetter { private val decorations = mutableListOf() private val persistentMarkers = mutableMapOf() - private val tempInsets = Insets() + private val insets = Insets() private val axisManager = AxisManager() - private val virtualLayout = VirtualLayout(axisManager) private val _markerTargets = sortedMapOf>() private val drawingModelAndLayerConsumer = @@ -102,6 +102,7 @@ public open class CartesianChart( public val layers: List> = layers.toList() /** The [CartesianChart]’s [ChartInsetter]s (persistent [CartesianMarker]s). */ + @Deprecated("This is no longer used. Consumers aren’t expected to require this property.") public val chartInsetters: Collection = persistentMarkers.values /** Links _x_ values to [CartesianMarker.Target]s. */ @@ -139,10 +140,11 @@ public open class CartesianChart( context: CartesianMeasureContext, model: CartesianChartModel, horizontalDimensions: MutableHorizontalDimensions, - bounds: RectF, + canvasBounds: RectF, marker: CartesianMarker?, ) { _markerTargets.clear() + insets.clear() model.forEachWithLayer( horizontalDimensionUpdateModelAndLayerConsumer.apply { this.context = context @@ -153,7 +155,29 @@ public open class CartesianChart( topAxis?.updateHorizontalDimensions(context, horizontalDimensions) endAxis?.updateHorizontalDimensions(context, horizontalDimensions) bottomAxis?.updateHorizontalDimensions(context, horizontalDimensions) - virtualLayout.setBounds(context, bounds, this, legend, horizontalDimensions, marker) + val insetters = buildList { + add(this@CartesianChart) + addAll(axisManager.axisCache) + if (marker != null) add(marker) + addAll(persistentMarkers.values) + } + insetters.forEach { it.updateInsets(context, horizontalDimensions, insets) } + val legendHeight = legend?.getHeight(context, canvasBounds.width()).orZero + val freeHeight = canvasBounds.height() - insets.vertical - legendHeight + insetters.forEach { it.updateHorizontalInsets(context, freeHeight, insets) } + setBounds( + canvasBounds.left + insets.getLeft(context.isLtr), + canvasBounds.top + insets.top, + canvasBounds.right - insets.getRight(context.isLtr), + canvasBounds.bottom - insets.bottom - legendHeight, + ) + axisManager.setAxesBounds(context, canvasBounds, bounds, insets) + legend?.setBounds( + left = canvasBounds.left, + top = bounds.bottom + insets.bottom, + right = canvasBounds.right, + bottom = bounds.bottom + insets.bottom + legendHeight, + ) } /** Draws the [CartesianChart]. */ @@ -188,24 +212,20 @@ public open class CartesianChart( ) } - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ) { - tempInsets.clear() - layers.forEach { it.getInsets(context, tempInsets, horizontalDimensions) } - outInsets.setValuesIfGreater(tempInsets) + layers.forEach { it.updateInsets(context, horizontalDimensions, insets) } } - override fun getHorizontalInsets( + override fun updateHorizontalInsets( context: CartesianMeasureContext, - availableHeight: Float, - outInsets: HorizontalInsets, + freeHeight: Float, + insets: HorizontalInsets, ) { - tempInsets.clear() - layers.forEach { it.getHorizontalInsets(context, availableHeight, tempInsets) } - outInsets.setValuesIfGreater(start = tempInsets.start, end = tempInsets.end) + layers.forEach { it.updateHorizontalInsets(context, freeHeight, insets) } } /** Prepares the [CartesianLayer]s for a difference animation. */ diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/ChartInsetter.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/ChartInsetter.kt index 0630f0274..964f50ba4 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/ChartInsetter.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/ChartInsetter.kt @@ -25,33 +25,33 @@ import com.patrykandpatrick.vico.core.cartesian.marker.CartesianMarker */ public interface ChartInsetter { /** - * Called during the measurement phase, before [getHorizontalInsets]. Both horizontal and vertical - * insets can be requested from this function. The final inset for a given edge of the associated - * [CartesianChart] is the largest of the insets requested for the edge. + * Called during the measurement phase, before [updateHorizontalInsets]. Both horizontal and + * vertical insets can be requested from this function. The final inset for a given edge of the + * associated [CartesianChart] is the largest of the insets requested for the edge. * * @param context holds data used for the measuring of components. - * @param outInsets used to store the requested insets. * @param horizontalDimensions the [CartesianChart]’s [HorizontalDimensions]. + * @param insets used to store the requested insets. */ - public fun getInsets( + public fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, - ): Unit = Unit + insets: Insets, + ) {} /** - * Called during the measurement phase, after [getInsets]. Only horizontal insets can be requested - * from this function. Unless the available height is of interest, [getInsets] can be used to set - * all insets. The final inset for a given edge of the associated [CartesianChart] is the largest - * of the insets requested for the edge. + * Called during the measurement phase, after [updateInsets]. Only horizontal insets can be + * requested from this function. Unless the available height is of interest, [updateInsets] can be + * used to set all insets. The final inset for a given edge of the associated [CartesianChart] is + * the largest of the insets requested for the edge. * * @param context holds data used for the measuring of components. - * @param availableHeight the available height. The vertical insets are considered here. - * @param outInsets used to store the requested insets. + * @param freeHeight the available height. The vertical insets are considered here. + * @param insets used to store the requested insets. */ - public fun getHorizontalInsets( + public fun updateHorizontalInsets( context: CartesianMeasureContext, - availableHeight: Float, - outInsets: HorizontalInsets, - ): Unit = Unit + freeHeight: Float, + insets: HorizontalInsets, + ) {} } diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/HorizontalInsets.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/HorizontalInsets.kt index 7d8033214..169185f8c 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/HorizontalInsets.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/HorizontalInsets.kt @@ -23,12 +23,29 @@ package com.patrykandpatrick.vico.core.cartesian * @see Insets */ public interface HorizontalInsets { - /** Sets the start and end insets. */ - public fun set(start: Float, end: Float) - - /** - * For the start and end insets, updates the value of the inset to the corresponding provided - * value if the provided value is greater than the current value. - */ - public fun setValuesIfGreater(start: Float, end: Float) + /** The start inset’s size (in pixels). */ + public val start: Float + + /** The end inset’s size (in pixels). */ + public val end: Float + + /** The sum of [start] and [end]. */ + public val horizontal: Float + get() = start + end + + /** Returns the left inset’s size (in pixels). */ + public fun getLeft(isLtr: Boolean): Float = if (isLtr) start else end + + /** Returns the right inset’s size (in pixels). */ + public fun getRight(isLtr: Boolean): Float = if (isLtr) end else start + + /** Ensures that the stored values are no smaller than the provided ones. */ + public fun ensureValuesAtLeast(start: Float = this.start, end: Float = this.end) + + /** Ensures that the stored values are no smaller than the provided ones. */ + @Suppress("DeprecatedCallableAddReplaceWith") + @Deprecated("Use `ensureValuesAtLeast`.") + public fun setValuesIfGreater(start: Float, end: Float) { + ensureValuesAtLeast(start, end) + } } diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/Insets.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/Insets.kt index b0bc85091..2777401a3 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/Insets.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/Insets.kt @@ -16,127 +16,82 @@ package com.patrykandpatrick.vico.core.cartesian -import com.patrykandpatrick.vico.core.common.half -import kotlin.math.max - /** * Used to store the insets requested by [ChartInsetter]s. * - * @param start the start inset. - * @param top the top inset. - * @param end the end inset. - * @param bottom the bottom inset. * @see ChartInsetter */ -public class Insets( - public var start: Float = 0f, - public var top: Float = 0f, - public var end: Float = 0f, - public var bottom: Float = 0f, -) : HorizontalInsets { - /** The sum of the sizes of the start inset and the end inset. */ - public val horizontal: Float - get() = start + end +public class Insets : HorizontalInsets { + /** The start inset’s size (in pixels). */ + public override var start: Float = 0f + private set + + /** The top inset’s size (in pixels). */ + public var top: Float = 0f + private set + + /** The end inset’s size (in pixels). */ + public override var end: Float = 0f + private set - /** The sum of the sizes of the top inset and the bottom inset. */ + /** The bottom inset’s size (in pixels). */ + public var bottom: Float = 0f + private set + + /** The sum of [top] and [bottom]. */ public val vertical: Float get() = top + bottom - /** The largest of the four insets. */ + /** The largest of [start], [top], [end], and [bottom]. */ public val max: Float get() = maxOf(start, top, end, bottom) - /** - * Updates the size of each of the four insets to match the size of its corresponding inset from - * the provided [Insets] instance. - */ - public fun set(other: Insets): Insets = set(other.start, other.top, other.end, other.bottom) - - /** Sets a common size for all four insets. */ - public fun set(all: Float): Insets = set(all, all, all, all) - - /** Updates the size of each of the four insets individually. */ - public fun set(start: Float = 0f, top: Float = 0f, end: Float = 0f, bottom: Float = 0f): Insets = - apply { - this.start = start - this.top = top - this.end = end - this.bottom = bottom - } - - /** Updates the sizes of the start inset and the end inset. */ - override fun set(start: Float, end: Float) { - this.start = start - this.end = end - } - - /** - * Returns the size of the left inset, taking into account the layout direction. - * - * @param isLtr whether the layout is left-to-right. - */ - public fun getLeft(isLtr: Boolean): Float = if (isLtr) start else end - - /** - * Returns the size of the right inset, taking into account the layout direction. - * - * @param isLtr whether the layout is left-to-right. - */ - public fun getRight(isLtr: Boolean): Float = if (isLtr) end else start - - /** - * Sets the sizes of the start inset and the end inset. [value] represents the sum of the two - * insets’ sizes, meaning the size of either inset will be half of [value]. - */ - public fun setHorizontal(value: Float): Insets = apply { - start = value.half - end = value.half - } - - /** - * Sets the sizes of the top inset and the bottom inset. [value] represents the sum of the two - * insets’ sizes, meaning the size of either inset will be half of [value]. - */ - public fun setVertical(value: Float): Insets = apply { - top = value.half - bottom = value.half - } - - override fun setValuesIfGreater(start: Float, end: Float) { - this.start = max(start, this.start) - this.end = max(end, this.end) + override fun ensureValuesAtLeast(start: Float, end: Float) { + this.start = this.start.coerceAtLeast(start) + this.end = this.end.coerceAtLeast(end) } - /** - * For each of the four insets, updates the size of the inset to the size of the corresponding - * inset from the provided [Insets] instance if the size of the corresponding inset from the - * provided [Insets] instance is greater. - */ - public fun setValuesIfGreater(other: Insets) { - start = max(start, other.start) - top = max(top, other.top) - end = max(end, other.end) - bottom = max(bottom, other.bottom) + /** Ensures that the stored values are no smaller than the provided ones. */ + public fun ensureValuesAtLeast( + start: Float = this.start, + top: Float = this.top, + end: Float = this.end, + bottom: Float = this.bottom, + ) { + this.start = this.start.coerceAtLeast(start) + this.top = this.top.coerceAtLeast(top) + this.end = this.end.coerceAtLeast(end) + this.bottom = this.bottom.coerceAtLeast(bottom) } - /** - * For each of the four insets, updates the size of the inset to the corresponding provided value - * if the corresponding provided value is greater. - */ + /** Ensures that the stored values are no smaller than the provided ones. */ + @Deprecated( + "Use `ensureValuesAtLeast`.", + ReplaceWith("ensureValuesAtLeast(start, top, end, bottom)"), + ) public fun setAllIfGreater( start: Float = this.start, top: Float = this.top, end: Float = this.end, bottom: Float = this.bottom, ) { - this.start = max(start, this.start) - this.top = max(top, this.top) - this.end = max(end, this.end) - this.bottom = max(bottom, this.bottom) + ensureValuesAtLeast(start, top, end, bottom) + } + + /** Ensures that the stored values are no smaller than those in [other]. */ + @Deprecated( + "Use `ensureValuesAtLeast`.", + ReplaceWith("ensureValuesAtLeast(other.start, other.top, other.end, other.bottom)"), + ) + public fun setValuesIfGreater(other: Insets) { + ensureValuesAtLeast(other.start, other.top, other.end, other.bottom) } - /** Sets the size of each of the four insets to zero. */ + /** Clears the stored values. */ public fun clear() { - set(0f) + start = 0f + top = 0f + end = 0f + bottom = 0f } } diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/VirtualLayout.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/VirtualLayout.kt deleted file mode 100644 index d8ee427c5..000000000 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/VirtualLayout.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2024 by Patryk Goworowski and Patrick Michalik. - * - * 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. - */ - -package com.patrykandpatrick.vico.core.cartesian - -import android.graphics.RectF -import com.patrykandpatrick.vico.core.cartesian.axis.AxisManager -import com.patrykandpatrick.vico.core.common.Legend -import com.patrykandpatrick.vico.core.common.orZero - -internal class VirtualLayout(private val axisManager: AxisManager) { - private val tempInsetters = ArrayList(TEMP_INSETTERS_INITIAL_SIZE) - - private val finalInsets: Insets = Insets() - - private val tempInsets: Insets = Insets() - - /** - * Measures and sets the bounds for the components of the chart. - * - * @param context holds data used for the measuring of components. - * @param contentBounds the bounds in which the chart should be drawn. - * @param chart the chart itself. - * @param legend the legend for the chart. - * @param horizontalDimensions the [HorizontalDimensions] of the chart. - * @param chartInsetter additional components that influence the chart layout, such as markers. - * @return the bounds applied to the chart. - */ - fun setBounds( - context: CartesianMeasureContext, - contentBounds: RectF, - chart: CartesianChart, - legend: Legend?, - horizontalDimensions: HorizontalDimensions, - vararg chartInsetter: ChartInsetter?, - ): RectF = - with(context) { - tempInsetters.clear() - finalInsets.clear() - tempInsets.clear() - - val legendHeight = legend?.getHeight(context, contentBounds.width()).orZero - - axisManager.addInsetters(tempInsetters) - chartInsetter.filterNotNull().forEach(tempInsetters::add) - tempInsetters.addAll(chart.chartInsetters) - tempInsetters.add(chart) - - tempInsetters.forEach { insetter -> - insetter.getInsets(context, tempInsets, horizontalDimensions) - finalInsets.setValuesIfGreater(tempInsets) - } - - val availableHeight = contentBounds.height() - finalInsets.vertical - legendHeight - - tempInsetters.forEach { insetter -> - insetter.getHorizontalInsets(context, availableHeight, tempInsets) - finalInsets.setValuesIfGreater(tempInsets) - } - - val chartBounds = - RectF().apply { - left = contentBounds.left + finalInsets.getLeft(isLtr) - top = contentBounds.top + finalInsets.top - right = contentBounds.right - finalInsets.getRight(isLtr) - bottom = contentBounds.bottom - finalInsets.bottom - legendHeight - } - - chart.setBounds( - left = chartBounds.left, - top = chartBounds.top, - right = chartBounds.right, - bottom = chartBounds.bottom, - ) - - axisManager.setAxesBounds(context, contentBounds, chartBounds, finalInsets) - - legend?.setBounds( - left = contentBounds.left, - top = chart.bounds.bottom + finalInsets.bottom, - right = contentBounds.right, - bottom = chart.bounds.bottom + finalInsets.bottom + legendHeight, - ) - - chartBounds - } - - private companion object { - const val TEMP_INSETTERS_INITIAL_SIZE = 5 - } -} diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/AxisManager.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/AxisManager.kt index 5df79c4e1..787ccc005 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/AxisManager.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/AxisManager.kt @@ -19,7 +19,6 @@ package com.patrykandpatrick.vico.core.cartesian.axis import android.graphics.RectF import com.patrykandpatrick.vico.core.cartesian.CartesianDrawContext import com.patrykandpatrick.vico.core.cartesian.CartesianMeasureContext -import com.patrykandpatrick.vico.core.cartesian.ChartInsetter import com.patrykandpatrick.vico.core.cartesian.Insets import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -32,42 +31,35 @@ internal class AxisManager { var endAxis: Axis? by cacheInList() var bottomAxis: Axis? by cacheInList() - fun addInsetters(destination: MutableList) { - startAxis?.let(destination::add) - topAxis?.let(destination::add) - endAxis?.let(destination::add) - bottomAxis?.let(destination::add) - } - fun setAxesBounds( measureContext: CartesianMeasureContext, - contentBounds: RectF, + canvasBounds: RectF, chartBounds: RectF, insets: Insets, ) { startAxis?.setStartAxisBounds( context = measureContext, - contentBounds = contentBounds, + canvasBounds = canvasBounds, chartBounds = chartBounds, insets = insets, ) topAxis?.setTopAxisBounds( context = measureContext, - contentBounds = contentBounds, + canvasBounds = canvasBounds, insets = insets, ) endAxis?.setEndAxisBounds( context = measureContext, - contentBounds = contentBounds, + canvasBounds = canvasBounds, chartBounds = chartBounds, insets = insets, ) bottomAxis?.setBottomAxisBounds( context = measureContext, - contentBounds = contentBounds, + canvasBounds = canvasBounds, chartBounds = chartBounds, insets = insets, ) @@ -77,15 +69,15 @@ internal class AxisManager { private fun Axis.setStartAxisBounds( context: CartesianMeasureContext, - contentBounds: RectF, + canvasBounds: RectF, chartBounds: RectF, insets: Insets, ) { with(context) { setBounds( - left = if (isLtr) contentBounds.left else contentBounds.right - insets.start, + left = if (isLtr) canvasBounds.left else canvasBounds.right - insets.start, top = chartBounds.top, - right = if (isLtr) contentBounds.left + insets.start else contentBounds.right, + right = if (isLtr) canvasBounds.left + insets.start else canvasBounds.right, bottom = chartBounds.bottom, ) } @@ -93,30 +85,30 @@ internal class AxisManager { private fun Axis.setTopAxisBounds( context: CartesianMeasureContext, - contentBounds: RectF, + canvasBounds: RectF, insets: Insets, ) { with(context) { setBounds( - left = contentBounds.left + if (isLtr) insets.start else insets.end, - top = contentBounds.top, - right = contentBounds.right - if (isLtr) insets.end else insets.start, - bottom = contentBounds.top + insets.top, + left = canvasBounds.left + if (isLtr) insets.start else insets.end, + top = canvasBounds.top, + right = canvasBounds.right - if (isLtr) insets.end else insets.start, + bottom = canvasBounds.top + insets.top, ) } } private fun Axis.setEndAxisBounds( context: CartesianMeasureContext, - contentBounds: RectF, + canvasBounds: RectF, chartBounds: RectF, insets: Insets, ) { with(context) { setBounds( - left = if (isLtr) contentBounds.right - insets.end else contentBounds.left, + left = if (isLtr) canvasBounds.right - insets.end else canvasBounds.left, top = chartBounds.top, - right = if (isLtr) contentBounds.right else contentBounds.left + insets.end, + right = if (isLtr) canvasBounds.right else canvasBounds.left + insets.end, bottom = chartBounds.bottom, ) } @@ -124,15 +116,15 @@ internal class AxisManager { private fun Axis.setBottomAxisBounds( context: CartesianMeasureContext, - contentBounds: RectF, + canvasBounds: RectF, chartBounds: RectF, insets: Insets, ) { with(context) { setBounds( - left = contentBounds.left + if (isLtr) insets.start else insets.end, + left = canvasBounds.left + if (isLtr) insets.start else insets.end, top = chartBounds.bottom, - right = contentBounds.right - if (isLtr) insets.end else insets.start, + right = canvasBounds.right - if (isLtr) insets.end else insets.start, bottom = chartBounds.bottom + insets.bottom, ) } 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 20ab702cd..c80eddd54 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 @@ -275,34 +275,37 @@ public open class HorizontalAxis( } } - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ) { val maxLabelWidth = context.getMaxLabelWidth(horizontalDimensions, context.getFullXRange(horizontalDimensions)) - with(outInsets) { + insets.ensureValuesAtLeast( start = itemPlacer.getStartHorizontalAxisInset( context, horizontalDimensions, context.tickThickness, maxLabelWidth, - ) + ), + top = + if (position.isTop) getDesiredHeight(context, horizontalDimensions, maxLabelWidth) else 0f, end = itemPlacer.getEndHorizontalAxisInset( context, horizontalDimensions, context.tickThickness, maxLabelWidth, - ) - top = - if (position.isTop) getDesiredHeight(context, horizontalDimensions, maxLabelWidth) else 0f + ), bottom = - if (position.isBottom) getDesiredHeight(context, horizontalDimensions, maxLabelWidth) - else 0f - } + if (position.isBottom) { + getDesiredHeight(context, horizontalDimensions, maxLabelWidth) + } else { + 0f + }, + ) } protected fun CartesianMeasureContext.getFullXRange( diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/VerticalAxis.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/VerticalAxis.kt index b7af7e990..618dd3b2c 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/VerticalAxis.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/axis/VerticalAxis.kt @@ -215,29 +215,29 @@ public open class VerticalAxis(override val po } } - override fun getHorizontalInsets( + override fun updateHorizontalInsets( context: CartesianMeasureContext, - availableHeight: Float, - outInsets: HorizontalInsets, + freeHeight: Float, + insets: HorizontalInsets, ): Unit = with(context) { - val desiredWidth = getDesiredWidth(this, availableHeight) + val desiredWidth = getDesiredWidth(this, freeHeight) - outInsets.set( + insets.ensureValuesAtLeast( start = if (position.isStart) desiredWidth else 0f, end = if (position.isEnd) desiredWidth else 0f, ) } - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ): Unit = with(context) { val maxLabelHeight = getMaxLabelHeight() val maxLineThickness = maxOf(axisThickness, tickThickness) - outInsets.set( + insets.ensureValuesAtLeast( top = itemPlacer.getTopVerticalAxisInset( context, @@ -259,7 +259,7 @@ public open class VerticalAxis(override val po * Calculates the optimal width for this [VerticalAxis], accounting for the value of * [sizeConstraint]. */ - protected open fun getDesiredWidth(context: CartesianMeasureContext, height: Float): Float = + protected open fun getDesiredWidth(context: CartesianMeasureContext, freeHeight: Float): Float = with(context) { when (val constraint = sizeConstraint) { is SizeConstraint.Auto -> { @@ -277,7 +277,7 @@ public open class VerticalAxis(override val po val labelSpace = when (horizontalLabelPosition) { Outside -> { - val maxLabelWidth = getMaxLabelWidth(height).ceil + val maxLabelWidth = getMaxLabelWidth(freeHeight).ceil extraStore[maxLabelWidthKey] = maxLabelWidth maxLabelWidth + tickLength } diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/BaseCartesianLayer.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/BaseCartesianLayer.kt index da89a0c43..0018ae58f 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/BaseCartesianLayer.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/BaseCartesianLayer.kt @@ -53,7 +53,7 @@ public abstract class BaseCartesianLayer : CartesianLay override fun draw(context: CartesianDrawContext, model: T) { with(context) { insets.clear() - getInsets(this, insets, horizontalDimensions) + updateInsets(this, horizontalDimensions, insets) canvas.inClip( left = bounds.left - insets.getLeft(isLtr), top = bounds.top - insets.top, diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/LineCartesianLayer.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/LineCartesianLayer.kt index cf288655e..b8cb4f5df 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/LineCartesianLayer.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/layer/LineCartesianLayer.kt @@ -546,17 +546,17 @@ public open class LineCartesianLayer( ) } - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ): Unit = with(context) { - outInsets.setVertical( + val verticalInset = lines .maxOf { if (it.point != null) max(it.thicknessDp, it.pointSizeDp) else it.thicknessDp } .pixels - ) + insets.ensureValuesAtLeast(top = verticalInset, bottom = verticalInset) } override fun prepareForTransformation( diff --git a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/marker/DefaultCartesianMarker.kt b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/marker/DefaultCartesianMarker.kt index 133a16543..c6b6828ce 100644 --- a/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/marker/DefaultCartesianMarker.kt +++ b/vico/core/src/main/java/com/patrykandpatrick/vico/core/cartesian/marker/DefaultCartesianMarker.kt @@ -200,18 +200,18 @@ public open class DefaultCartesianMarker( .forEach { x -> guideline?.drawVertical(this, chartBounds.top, chartBounds.bottom, x) } } - override fun getInsets( + override fun updateInsets( context: CartesianMeasureContext, - outInsets: Insets, horizontalDimensions: HorizontalDimensions, + insets: Insets, ) { with(context) { when (labelPosition) { LabelPosition.Top, LabelPosition.AbovePoint -> - outInsets.top = label.getHeight(context) + label.tickSizeDp.pixels + insets.ensureValuesAtLeast(top = label.getHeight(context) + label.tickSizeDp.pixels) LabelPosition.Bottom -> - outInsets.bottom = label.getHeight(context) + label.tickSizeDp.pixels + insets.ensureValuesAtLeast(bottom = label.getHeight(context) + label.tickSizeDp.pixels) LabelPosition.AroundPoint -> Unit // Will be inside the chart } } diff --git a/vico/views/src/main/java/com/patrykandpatrick/vico/views/cartesian/CartesianChartView.kt b/vico/views/src/main/java/com/patrykandpatrick/vico/views/cartesian/CartesianChartView.kt index b02829a56..828085c29 100644 --- a/vico/views/src/main/java/com/patrykandpatrick/vico/views/cartesian/CartesianChartView.kt +++ b/vico/views/src/main/java/com/patrykandpatrick/vico/views/cartesian/CartesianChartView.kt @@ -69,7 +69,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 override val measureContext: MutableCartesianMeasureContext = MutableCartesianMeasureContext( - canvasBounds = contentBounds, + canvasBounds = canvasBounds, density = context.density, isLtr = context.isLtr, scrollEnabled = false, @@ -322,7 +322,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 withChartAndModel { chart, model -> measureContext.reset() horizontalDimensions.clear() - chart.prepare(measureContext, model, horizontalDimensions, contentBounds, marker) + chart.prepare(measureContext, model, horizontalDimensions, canvasBounds, marker) if (chart.bounds.isEmpty) return@withChartAndModel diff --git a/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/BaseChartView.kt b/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/BaseChartView.kt index f5f513dbf..791add694 100644 --- a/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/BaseChartView.kt +++ b/vico/views/src/main/java/com/patrykandpatrick/vico/views/common/BaseChartView.kt @@ -50,11 +50,11 @@ public abstract class BaseChartView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : FrameLayout(context, attrs, defStyleAttr) { - protected val contentBounds: RectF = RectF() + protected val canvasBounds: RectF = RectF() protected open val measureContext: MutableMeasureContext = MutableMeasureContext( - canvasBounds = contentBounds, + canvasBounds = canvasBounds, density = context.density, isLtr = context.isLtr, spToPx = context::spToPx, @@ -151,7 +151,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), ) - contentBounds.set( + canvasBounds.set( left = paddingLeft, top = paddingTop, right = width - paddingRight,