Skip to content

Commit

Permalink
ensure currentRange is not set beyond maxViewExtent. Prevent inadvert…
Browse files Browse the repository at this point in the history
…ent panning if zoom is at min/max extent.
  • Loading branch information
gsteckman committed Nov 7, 2024
1 parent 30e32f4 commit f291da4
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,24 @@ public class DoubleLinearAxisModel(
"Axis range end (${range.endInclusive}) must be greater than start (${range.start})"
}
require(minimumMajorTickSpacing > 0.dp) { "Minimum major tick spacing must be greater than 0 dp" }
require(minViewExtent > 0f) {
"Zoom range limit must be greater than 0"
require(minViewExtent > 0.0) {
"minViewExtent must be greater than 0"
}
require(maxViewExtent > 0.0 && maxViewExtent >= minViewExtent) {
"maxViewExtent must be greater than 0 and greater than or equal to minViewExtent"
}
require(minViewExtent <= range.endInclusive - range.start) {
"minViewExtent must be less than or equal to range"
}
require(maxViewExtent <= range.endInclusive - range.start) {
"maxViewExtent must be less than or equal to range"
}
require(minViewExtent < range.endInclusive - range.start) { "Zoom range limit must be less than range" }
require(minimumMajorTickIncrement <= range.endInclusive - range.start) {
"minimumMajorTickIncrement must be less than or equal to the axis range"
}
}

private var currentRange by mutableStateOf(range)
private var currentRange by mutableStateOf(range.start..(range.start + maxViewExtent))

override fun computeOffset(point: Double): Float {
return ((point - currentRange.start) / (currentRange.endInclusive - currentRange.start)).toFloat()
Expand Down Expand Up @@ -165,14 +173,20 @@ public class DoubleLinearAxisModel(
require(zoomFactor > 0) { "Zoom amount must be greater than 0" }
require(pivot in 0.0..1.0) { "Zoom pivot must be between 0 and 1: $pivot" }

// convert pivot to axis range space
val pivotAxisScale =
(currentRange.start) + (currentRange.endInclusive - currentRange.start) * pivot
if (zoomFactor > 1f && currentRange.endInclusive - currentRange.start == minViewExtent) {
// Can't zoom in more
} else if (zoomFactor < 1f && currentRange.endInclusive - currentRange.start == maxViewExtent) {
// Can't zoom out more
} else {
// convert pivot to axis range space
val pivotAxisScale =
(currentRange.start) + (currentRange.endInclusive - currentRange.start) * pivot

val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.start) / zoomFactor).coerceIn(range)
val newHi = (pivotAxisScale + (currentRange.endInclusive - pivotAxisScale) / zoomFactor).coerceIn(range)
val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.start) / zoomFactor)
val newHi = (pivotAxisScale + (currentRange.endInclusive - pivotAxisScale) / zoomFactor)

setViewRange(newLow..newHi)
setViewRange(newLow..newHi)
}
}

override fun pan(amount: Float) {
Expand All @@ -192,8 +206,8 @@ public class DoubleLinearAxisModel(
}

override fun setViewRange(newRange: ClosedRange<Double>) {
val newHi = newRange.endInclusive
val newLow = newRange.start
val newHi = newRange.endInclusive.coerceIn(range)
val newLow = newRange.start.coerceIn(range)

if (newHi - newLow < minViewExtent) {
val delta = (minViewExtent - (newHi - newLow)) / 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,23 @@ public class FloatLinearAxisModel(
}
require(minimumMajorTickSpacing > 0.dp) { "Minimum major tick spacing must be greater than 0 dp" }
require(minViewExtent > 0f) {
"Zoom range limit must be greater than 0"
"minViewExtent must be greater than 0"
}
require(maxViewExtent > 0f && maxViewExtent >= minViewExtent) {
"maxViewExtent must be greater than 0 and greater than or equal to minViewExtent"
}
require(minViewExtent <= range.endInclusive - range.start) {
"minViewExtent must be less than or equal to range"
}
require(maxViewExtent <= range.endInclusive - range.start) {
"maxViewExtent must be less than or equal to range"
}
require(minViewExtent < range.endInclusive - range.start) { "Zoom range limit must be less than range" }
require(minimumMajorTickIncrement <= range.endInclusive - range.start) {
"minimumMajorTickIncrement must be less than or equal to the axis range"
}
}

internal var currentRange by mutableStateOf(range)
internal var currentRange by mutableStateOf(range.start..(range.start + maxViewExtent))

override fun computeOffset(point: Float): Float {
return (point - currentRange.start) / (currentRange.endInclusive - currentRange.start)
Expand Down Expand Up @@ -166,14 +174,19 @@ public class FloatLinearAxisModel(
require(zoomFactor > 0) { "Zoom amount must be greater than 0" }
require(pivot in 0.0..1.0) { "Zoom pivot must be between 0 and 1: $pivot" }

// convert pivot to axis range space
val pivotAxisScale =
(currentRange.start) + (currentRange.endInclusive - currentRange.start) * pivot
if (zoomFactor > 1f && currentRange.endInclusive - currentRange.start == minViewExtent) {
// Can't zoom in more
} else if (zoomFactor < 1f && currentRange.endInclusive - currentRange.start == maxViewExtent) {
// Can't zoom out more
} else {
// convert pivot to axis range space
val pivotAxisScale = (currentRange.start) + (currentRange.endInclusive - currentRange.start) * pivot

val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.start) / zoomFactor).coerceIn(range)
val newHi = (pivotAxisScale + (currentRange.endInclusive - pivotAxisScale) / zoomFactor).coerceIn(range)
val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.start) / zoomFactor)
val newHi = (pivotAxisScale + (currentRange.endInclusive - pivotAxisScale) / zoomFactor)

setViewRange(newLow..newHi)
setViewRange(newLow..newHi)
}
}

override fun pan(amount: Float) {
Expand All @@ -193,8 +206,8 @@ public class FloatLinearAxisModel(
}

override fun setViewRange(newRange: ClosedRange<Float>) {
val newHi = newRange.endInclusive
val newLow = newRange.start
val newHi = newRange.endInclusive.coerceIn(range)
val newLow = newRange.start.coerceIn(range)

if (newHi - newLow < minViewExtent) {
val delta = (minViewExtent - (newHi - newLow)) / 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public class IntLinearAxisModel(
}

// Internal for testing
internal var currentRange by mutableStateOf(range)
internal var currentRange by mutableStateOf(range.first..(range.first + maxViewExtent))

override fun computeOffset(point: Int): Float {
return ((point - currentRange.first).toFloat() / (currentRange.last - currentRange.first).toFloat())
Expand Down Expand Up @@ -171,13 +171,19 @@ public class IntLinearAxisModel(
require(zoomFactor > 0) { "Zoom amount must be greater than 0" }
require(pivot in 0.0..1.0) { "Zoom pivot must be between 0 and 1: $pivot" }

// convert pivot to axis range space
val pivotAxisScale = currentRange.first + ((currentRange.last - currentRange.first) * pivot).roundToInt()
if (zoomFactor > 1f && currentRange.last - currentRange.first == minViewExtent) {
// Can't zoom in more
} else if (zoomFactor < 1f && currentRange.last - currentRange.first == maxViewExtent) {
// Can't zoom out more
} else {
// convert pivot to axis range space
val pivotAxisScale = currentRange.first + ((currentRange.last - currentRange.first) * pivot).roundToInt()

val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.first) / zoomFactor).roundToInt().coerceIn(range)
val newHi = (pivotAxisScale + (currentRange.last - pivotAxisScale) / zoomFactor).roundToInt().coerceIn(range)
val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.first) / zoomFactor).roundToInt()
val newHi = (pivotAxisScale + (currentRange.last - pivotAxisScale) / zoomFactor).roundToInt()

setViewRange(newLow..newHi)
setViewRange(newLow..newHi)
}
}

override fun pan(amount: Float) {
Expand All @@ -197,8 +203,8 @@ public class IntLinearAxisModel(
}

override fun setViewRange(newRange: ClosedRange<Int>) {
val newHi = newRange.endInclusive
val newLow = newRange.start
val newHi = newRange.endInclusive.coerceIn(range)
val newLow = newRange.start.coerceIn(range)

if (newHi - newLow < minViewExtent) {
val delta = (minViewExtent - (newHi - newLow)) / 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,24 @@ public class LongLinearAxisModel(
"Axis range end (${range.last}) must be greater than start (${range.first})"
}
require(minimumMajorTickSpacing > 0.dp) { "Minimum major tick spacing must be greater than 0 dp" }
require(minViewExtent > 0f) {
"Zoom range limit must be greater than 0"
require(minViewExtent > 0L) {
"minViewExtent must be greater than 0"
}
require(maxViewExtent > 0L && maxViewExtent >= minViewExtent) {
"maxViewExtent must be greater than 0 and greater than or equal to minViewExtent"
}
require(minViewExtent <= range.last - range.first) {
"minViewExtent must be less than or equal to range"
}
require(maxViewExtent <= range.last - range.first) {
"maxViewExtent must be less than or equal to range"
}
require(minViewExtent <= range.last - range.first) { "Zoom range limit must be less than or equal to range" }
require(minimumMajorTickIncrement <= range.last - range.first) {
"minimumMajorTickIncrement must be less than or equal to the axis range"
}
}

private var currentRange by mutableStateOf(range)
private var currentRange by mutableStateOf(range.first..(range.first + maxViewExtent))

override fun computeOffset(point: Long): Float {
return ((point - currentRange.first).toDouble() / (currentRange.last - currentRange.first).toDouble()).toFloat()
Expand Down Expand Up @@ -166,18 +174,20 @@ public class LongLinearAxisModel(
require(zoomFactor > 0) { "Zoom amount must be greater than 0" }
require(pivot in 0.0..1.0) { "Zoom pivot must be between 0 and 1: $pivot" }

// convert pivot to axis range space
val pivotAxisScale =
currentRange.first + ((currentRange.last - currentRange.first) * pivot.toDouble()).roundToLong()
if (zoomFactor > 1f && currentRange.last - currentRange.first == minViewExtent) {
// Can't zoom in more
} else if (zoomFactor < 1f && currentRange.last - currentRange.first == maxViewExtent) {
// Can't zoom out more
} else {
// convert pivot to axis range space
val pivotAxisScale =
currentRange.first + ((currentRange.last - currentRange.first) * pivot.toDouble()).roundToLong()

val newLow =
(pivotAxisScale - (pivotAxisScale - currentRange.first) / zoomFactor.toDouble()).roundToLong()
.coerceIn(range)
val newHi =
(pivotAxisScale + (currentRange.last - pivotAxisScale) / zoomFactor.toDouble()).roundToLong()
.coerceIn(range)
val newLow = (pivotAxisScale - (pivotAxisScale - currentRange.first) / zoomFactor.toDouble()).roundToLong()
val newHi = (pivotAxisScale + (currentRange.last - pivotAxisScale) / zoomFactor.toDouble()).roundToLong()

setViewRange(newLow..newHi)
setViewRange(newLow..newHi)
}
}

override fun pan(amount: Float) {
Expand All @@ -197,8 +207,8 @@ public class LongLinearAxisModel(
}

override fun setViewRange(newRange: ClosedRange<Long>) {
val newHi = newRange.endInclusive
val newLow = newRange.start
val newHi = newRange.endInclusive.coerceIn(range)
val newLow = newRange.start.coerceIn(range)

if (newHi - newLow < minViewExtent) {
val delta = (minViewExtent - (newHi - newLow)) / 2
Expand Down

0 comments on commit f291da4

Please sign in to comment.