Skip to content

Commit

Permalink
Improve HorizontalLayout, HorizontalDimensions, and related logic
Browse files Browse the repository at this point in the history
  • Loading branch information
patrickmichalik committed Jul 5, 2023
1 parent 20f102e commit 0aa2212
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ public class HorizontalAxis<Position : AxisPosition.Horizontal>(
val chartValues = chartValuesManager.getChartValues()

canvas.clipRect(
bounds.left - horizontalLayout.getStartHorizontalAxisInset(context, tickThickness),
bounds.left - horizontalLayout.getStartHorizontalAxisInset(horizontalDimensions, tickThickness),
minOf(bounds.top, chartBounds.top),
bounds.right + horizontalLayout.getEndHorizontalAxisInset(context, tickThickness),
bounds.right + horizontalLayout.getEndHorizontalAxisInset(horizontalDimensions, tickThickness),
maxOf(bounds.bottom, chartBounds.bottom),
)

Expand All @@ -78,14 +78,8 @@ public class HorizontalAxis<Position : AxisPosition.Horizontal>(
(abs((horizontalScroll - horizontalDimensions.startPadding).coerceAtLeast(0f)) / tickDrawStep).toInt()
val textY = if (position.isBottom) tickMarkBottom else tickMarkTop

val labelPositionOffset = when (horizontalLayout) {
is HorizontalLayout.Segmented -> tickDrawStep.half
is HorizontalLayout.FullWidth -> 0f
}

var textCenter = bounds.getStart(isLtr = isLtr) + layoutDirectionMultiplier *
(labelPositionOffset + tickDrawStep * scrollAdjustment) - horizontalScroll +
horizontalDimensions.startPadding
var textCenter = bounds.getStart(isLtr = isLtr) + layoutDirectionMultiplier * tickDrawStep * scrollAdjustment -
horizontalScroll + horizontalDimensions.startPadding

var tickCenter = getTickDrawCenter(horizontalScroll, tickDrawStep, scrollAdjustment, textCenter)

Expand Down Expand Up @@ -205,11 +199,12 @@ public class HorizontalAxis<Position : AxisPosition.Horizontal>(
outInsets: Insets,
horizontalDimensions: HorizontalDimensions,
): Unit = with(context) {
val scaledHorizontalDimensions = horizontalDimensions.scaled(chartScale)
with(outInsets) {
start = horizontalLayout.getStartHorizontalAxisInset(context, tickThickness)
end = horizontalLayout.getEndHorizontalAxisInset(context, tickThickness)
top = if (position.isTop) getDesiredHeight(context, horizontalDimensions) else 0f
bottom = if (position.isBottom) getDesiredHeight(context, horizontalDimensions) else 0f
start = horizontalLayout.getStartHorizontalAxisInset(scaledHorizontalDimensions, tickThickness)
end = horizontalLayout.getEndHorizontalAxisInset(scaledHorizontalDimensions, tickThickness)
top = if (position.isTop) getDesiredHeight(context, scaledHorizontalDimensions) else 0f
bottom = if (position.isBottom) getDesiredHeight(context, scaledHorizontalDimensions) else 0f
}
}

Expand All @@ -219,7 +214,7 @@ public class HorizontalAxis<Position : AxisPosition.Horizontal>(
): Float = with(context) {
val labelWidth =
if (isHorizontalScrollEnabled) {
horizontalDimensions.scaled(scale = chartScale).xSpacing.toInt() * labelSpacing
horizontalDimensions.xSpacing.toInt() * labelSpacing
} else {
Int.MAX_VALUE
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public open class ColumnChart(
model.entries.forEachIndexed { index, entryCollection ->

column = columns.getRepeating(index)
drawingStart = getDrawingStart(index) - horizontalScroll
drawingStart = getDrawingStart(index, model.entries.size) - horizontalScroll

entryCollection.forEachInRelativelyIndexed(chartValues.minX..chartValues.maxX) { entryIndex, entry ->

Expand Down Expand Up @@ -336,15 +336,19 @@ public open class ColumnChart(
model: ChartEntryModel,
): HorizontalDimensions = with(context) {
val columnCollectionWidth = getColumnCollectionWidth(model.entries.size)
val basePadding = when (horizontalLayout) {
is HorizontalLayout.Segmented -> 0f
is HorizontalLayout.FullWidth -> columnCollectionWidth.half
horizontalDimensions.apply {
xSpacing = columnCollectionWidth + spacingDp.pixels
when (horizontalLayout) {
is HorizontalLayout.Segmented -> {
scalableStartPadding = xSpacing.half
scalableEndPadding = scalableStartPadding
}
is HorizontalLayout.FullWidth -> {
scalableStartPadding = columnCollectionWidth.half + horizontalLayout.startPaddingDp.pixels
scalableEndPadding = columnCollectionWidth.half + horizontalLayout.endPaddingDp.pixels
}
}
}
horizontalDimensions.set(
xSpacing = columnCollectionWidth + spacingDp.pixels,
startPadding = basePadding + horizontalLayout.startPaddingDp.pixels,
endPadding = basePadding + horizontalLayout.endPaddingDp.pixels,
)
}

protected open fun MeasureContext.getColumnCollectionWidth(
Expand All @@ -357,18 +361,15 @@ public open class ColumnChart(
getCumulatedThickness(entryCollectionSize) + innerSpacingDp.pixels * (entryCollectionSize - 1)
}

protected open fun MeasureContext.getDrawingStart(entryCollectionIndex: Int): Float {
val horizontalLayoutComponent = when (horizontalLayout) {
is HorizontalLayout.Segmented -> spacingDp.half.pixels
is HorizontalLayout.FullWidth -> horizontalLayout.startPaddingDp.pixels
}
protected open fun MeasureContext.getDrawingStart(entryCollectionIndex: Int, entryCollectionCount: Int): Float {
val mergeModeComponent = when (mergeMode) {
MergeMode.Grouped ->
getCumulatedThickness(entryCollectionIndex) + innerSpacingDp.pixels * entryCollectionIndex

MergeMode.Stack -> 0f
}
return bounds.getStart(isLtr) + (horizontalLayoutComponent + mergeModeComponent) * chartScale *
return bounds.getStart(isLtr) + horizontalDimensions.scaled(chartScale).startPadding +
(mergeModeComponent - getColumnCollectionWidth(entryCollectionCount).half) * chartScale *
layoutDirectionMultiplier
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,10 @@ public class ComposedChart<Model : ChartEntryModel>(
val chartHorizontalDimensions = chart.getHorizontalDimensions(context, item)
horizontalDimensions.apply {
xSpacing = maxOf(xSpacing, chartHorizontalDimensions.xSpacing)
startPadding = maxOf(startPadding, chartHorizontalDimensions.startPadding)
endPadding = maxOf(endPadding, chartHorizontalDimensions.endPadding)
scalableStartPadding = maxOf(scalableStartPadding, chartHorizontalDimensions.scalableStartPadding)
scalableEndPadding = maxOf(scalableEndPadding, chartHorizontalDimensions.scalableEndPadding)
unscalableStartPadding = maxOf(unscalableStartPadding, chartHorizontalDimensions.unscalableStartPadding)
unscalableEndPadding = maxOf(unscalableEndPadding, chartHorizontalDimensions.unscalableEndPadding)
}
}
return horizontalDimensions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,42 +23,98 @@ import com.patrykandpatrick.vico.core.chart.Chart
*/
public interface HorizontalDimensions {
/**
* The distance between neighboring major entries (in pixels).
* The distance between neighboring major entries (in pixels). This can be scaled.
*/
public val xSpacing: Float

/**
* The distance between the start of the content area and the first entry (in pixels).
* The scalable part of the distance between the start of the content area and the first entry (in pixels).
*/
public val scalableStartPadding: Float

/**
* The scalable part of the distance between the end of the content area and the last entry (in pixels).
*/
public val scalableEndPadding: Float

/**
* The unscalable part of the distance between the start of the content area and the first entry (in pixels).
*/
public val unscalableStartPadding: Float

/**
* The unscalable part of the distance between the end of the content area and the last entry (in pixels).
*/
public val unscalableEndPadding: Float

/**
* The total start padding (in pixels).
*/
public val startPadding: Float
get() = scalableStartPadding + unscalableStartPadding

/**
* The distance between the end of the content area and the last entry (in pixels).
* The total end padding (in pixels).
*/
public val endPadding: Float
get() = scalableEndPadding + unscalableEndPadding

/**
* Creates a new [HorizontalDimensions] instance by multiplying this one’s values by the given factor.
* The total horizontal padding (in pixels).
*/
public fun scaled(scale: Float): HorizontalDimensions =
HorizontalDimensions(xSpacing * scale, startPadding * scale, endPadding * scale)
public val padding: Float
get() = startPadding + endPadding

/**
* Given the chart’s maximum number of major entries, calculates the width of the [Chart]’s content (in pixels).
*/
public fun getContentWidth(maxMajorEntryCount: Int): Float = xSpacing * (maxMajorEntryCount - 1) + padding

/**
* Creates a new [HorizontalDimensions] instance by multiplying this one’s scalable values by the given factor.
*/
public fun scaled(scale: Float): HorizontalDimensions = HorizontalDimensions(
xSpacing * scale,
scalableStartPadding * scale,
scalableEndPadding * scale,
unscalableStartPadding,
unscalableEndPadding,
)
}

/**
* Creates a [HorizontalDimensions] instance.
*/
public fun HorizontalDimensions(
xSpacing: Float,
startPadding: Float,
endPadding: Float,
scalableStartPadding: Float,
scalableEndPadding: Float,
unscalableStartPadding: Float,
unscalableEndPadding: Float,
): HorizontalDimensions = object : HorizontalDimensions {
override val xSpacing: Float = xSpacing
override val startPadding: Float = startPadding
override val endPadding: Float = endPadding
override val scalableStartPadding: Float = scalableStartPadding
override val scalableEndPadding: Float = scalableEndPadding
override val unscalableStartPadding: Float = unscalableStartPadding
override val unscalableEndPadding: Float = unscalableEndPadding
}

/**
* The total horizontal padding (in pixels).
* Creates a [HorizontalDimensions] instance.
*/
public val HorizontalDimensions.padding: Float
get() = startPadding + endPadding
@Deprecated(
"""`startPadding` and `endPadding` have been replaced by `scalableStartPadding`, `scalableEndPadding`,
`unscalableStartPadding`, and `unscalableEndPadding`. Use the overload with these parameters instead.""",
ReplaceWith("HorizontalDimensions(xSpacing, startPadding, endPadding, 0f, 0f)"),
)
public fun HorizontalDimensions(
xSpacing: Float,
startPadding: Float,
endPadding: Float,
): HorizontalDimensions = HorizontalDimensions(
xSpacing = xSpacing,
scalableStartPadding = startPadding,
unscalableEndPadding = endPadding,
scalableEndPadding = 0f,
unscalableStartPadding = 0f,
)
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,52 @@ package com.patrykandpatrick.vico.core.chart.dimensions
*/
public data class MutableHorizontalDimensions(
override var xSpacing: Float = 0f,
override var startPadding: Float = 0f,
override var endPadding: Float = 0f,
override var scalableStartPadding: Float = 0f,
override var scalableEndPadding: Float = 0f,
override var unscalableStartPadding: Float = 0f,
override var unscalableEndPadding: Float = 0f,
) : HorizontalDimensions {
/**
* Updates the stored values.
*/
public fun set(xSpacing: Float, startPadding: Float, endPadding: Float): MutableHorizontalDimensions = apply {
public fun set(
xSpacing: Float,
scalableStartPadding: Float,
scalableEndPadding: Float,
unscalableStartPadding: Float,
unscalableEndPadding: Float,
): MutableHorizontalDimensions = apply {
this.xSpacing = xSpacing
this.startPadding = startPadding
this.endPadding = endPadding
this.scalableStartPadding = scalableStartPadding
this.scalableEndPadding = scalableEndPadding
this.unscalableStartPadding = unscalableStartPadding
this.unscalableEndPadding = unscalableEndPadding
}

/**
* Updates the stored values.
*/
@Deprecated(
"""`startPadding` and `endPadding` have been replaced by `scalableStartPadding`, `scalableEndPadding`,
`unscalableStartPadding`, and `unscalableEndPadding`. Use the overload with these parameters instead.""",
ReplaceWith("set(xSpacing, startPadding, endPadding, 0f, 0f)"),
)
public fun set(xSpacing: Float, startPadding: Float, endPadding: Float): MutableHorizontalDimensions = set(
xSpacing = xSpacing,
scalableStartPadding = startPadding,
scalableEndPadding = endPadding,
unscalableStartPadding = 0f,
unscalableEndPadding = 0f,
)

/**
* Clears the stored values.
*/
public fun clear() {
xSpacing = 0f
startPadding = 0f
endPadding = 0f
scalableStartPadding = 0f
scalableEndPadding = 0f
unscalableStartPadding = 0f
unscalableEndPadding = 0f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package com.patrykandpatrick.vico.core.chart.draw
import android.graphics.RectF
import com.patrykandpatrick.vico.core.chart.Chart
import com.patrykandpatrick.vico.core.chart.dimensions.HorizontalDimensions
import com.patrykandpatrick.vico.core.chart.dimensions.padding
import com.patrykandpatrick.vico.core.context.DrawContext
import com.patrykandpatrick.vico.core.context.MeasureContext
import com.patrykandpatrick.vico.core.model.Point
Expand Down Expand Up @@ -57,12 +56,9 @@ public fun MeasureContext.getMaxScrollDistance(
chartWidth: Float,
horizontalDimensions: HorizontalDimensions,
): Float {
val contentWidth = (
horizontalLayout.getContentWidth(
horizontalDimensions.xSpacing,
chartValuesManager.getChartValues().getMaxMajorEntryCount(),
) + horizontalDimensions.padding
) * chartScale
val contentWidth = horizontalDimensions
.scaled(chartScale)
.getContentWidth(chartValuesManager.getChartValues().getMaxMajorEntryCount())

return (layoutDirectionMultiplier * (contentWidth - chartWidth)).run {
if (isLtr) coerceAtLeast(minimumValue = 0f) else coerceAtMost(maximumValue = 0f)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import android.graphics.Canvas
import android.graphics.RectF
import com.patrykandpatrick.vico.core.chart.Chart
import com.patrykandpatrick.vico.core.chart.dimensions.HorizontalDimensions
import com.patrykandpatrick.vico.core.chart.dimensions.padding
import com.patrykandpatrick.vico.core.chart.scale.AutoScaleUp
import com.patrykandpatrick.vico.core.component.shape.ShapeComponent
import com.patrykandpatrick.vico.core.context.DrawContext
Expand Down Expand Up @@ -79,10 +78,8 @@ public fun chartDrawContext(
}

private fun calculateDrawScale(): Float {
val contentWidth = horizontalLayout.getContentWidth(
horizontalDimensions.xSpacing,
chartValuesManager.getChartValues().getMaxMajorEntryCount(),
) + horizontalDimensions.padding
val contentWidth =
horizontalDimensions.getContentWidth(chartValuesManager.getChartValues().getMaxMajorEntryCount())
val upscalingPossibleButDisallowed = contentWidth < chartBounds.width() && autoScaleUp == AutoScaleUp.None
val scrollEnabledAndUpscalingImpossible = isHorizontalScrollEnabled && contentWidth >= chartBounds.width()
return if (upscalingPossibleButDisallowed || scrollEnabledAndUpscalingImpossible) {
Expand Down
Loading

0 comments on commit 0aa2212

Please sign in to comment.