Skip to content

Commit

Permalink
add on bar click and on bar long click for row/column charts,
Browse files Browse the repository at this point in the history
add id field to bars data
  • Loading branch information
ehsannarmani committed Jun 13, 2024
1 parent d1ca5a2 commit 1ed207c
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ fun RowScope.ColumnSample() {
containerColor = Color(0xff414141),
),
labelHelperProperties = LabelHelperProperties(textStyle = TextStyle(fontSize = 12.sp, fontFamily = ubuntu, color = Color.White)),
onBarClick = {
println(it)
},
onBarLongClick = {
println("long: $it")
}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,12 @@ fun RowScope.RowSample() {
},
containerColor = Color(0xff414141),
),
onBarClick = {
println("bar click: $it")
},
onBarLongClick = {
println("long click: $it")
}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand Down Expand Up @@ -68,6 +69,8 @@ fun ColumnChart(
modifier: Modifier = Modifier,
data: List<Bars>,
barProperties: BarProperties = BarProperties(),
onBarClick: ((Bars.Data) -> Unit)? = null,
onBarLongClick: ((Bars.Data) -> Unit)? = null,
labelProperties: LabelProperties = LabelProperties(
textStyle = TextStyle.Default,
enabled = true
Expand Down Expand Up @@ -115,8 +118,8 @@ fun ColumnChart(
}.average().toFloat()
}

val rectWithValue = remember {
mutableStateListOf<Pair<Double, Rect>>()
val barWithRect = remember {
mutableStateListOf<Pair<Bars.Data, Rect>>()
}

val selectedValue = remember {
Expand Down Expand Up @@ -155,7 +158,7 @@ fun ColumnChart(
spec = { it.animationSpec ?: animationSpec },
delay = animationDelay,
before = {
rectWithValue.clear()
barWithRect.clear()
}
)
Column(modifier = modifier) {
Expand All @@ -172,59 +175,75 @@ fun ColumnChart(
Canvas(modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
if (!popupProperties.enabled) return@pointerInput
detectDragGestures { change, dragAmount ->
rectWithValue
.lastOrNull { (value, rect) ->
change.position.x in rect.left..rect.right
}
?.let { (value, rect) ->
selectedValue.value = SelectedBar(
value = value,
rect = rect,
offset = Offset(
rect.left,
if (value < 0) rect.bottom else rect.top
)
)
scope.launch {
if (popupAnimation.value != 1f && !popupAnimation.isRunning) {
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
if (popupProperties.enabled) {
detectDragGestures { change, dragAmount ->
barWithRect
.lastOrNull { (value, rect) ->
change.position.x in rect.left..rect.right
}
?.let { (bar, rect) ->
selectedValue.value = SelectedBar(
bar = bar,
rect = rect,
offset = Offset(
rect.left,
if (bar.value < 0) rect.bottom else rect.top
)
)
scope.launch {
if (popupAnimation.value != 1f && !popupAnimation.isRunning) {
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
)
}
}
}
}
}
}
}
.pointerInteropFilter { event ->
if (event.action == MotionEvent.ACTION_DOWN && popupProperties.enabled) {
val position = Offset(event.x, event.y)
rectWithValue
.lastOrNull {
it.second.contains(position)
}
?.let { (value, rect) ->
selectedValue.value = SelectedBar(
value = value,
rect = rect,
offset = Offset(
rect.left,
if (value < 0) rect.bottom else rect.top
)
)
scope.launch {
popupAnimation.snapTo(0f)
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
)
.pointerInput(Unit) {
detectTapGestures(
onTap = {
val position = Offset(it.x, it.y)
barWithRect
.lastOrNull { (_, rect) ->
rect.contains(position)
}
}
}
false
}) {
?.let { (bar, rect) ->
if (popupProperties.enabled) {
selectedValue.value = SelectedBar(
bar = bar,
rect = rect,
offset = Offset(
rect.left,
if (bar.value < 0) rect.bottom else rect.top
)
)
scope.launch {
popupAnimation.snapTo(0f)
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
)
}
}
onBarClick?.invoke(bar)
}
},
onLongPress = {
val position = Offset(it.x, it.y)
barWithRect
.lastOrNull { (_, rect) ->
rect.contains(position)
}
?.let { (bar, _) ->
onBarLongClick?.invoke(bar)
}
}
)
}
) {

val barsAreaWidth = size.width - (indicatorAreaWidth)
val zeroY = size.height - calculateOffset(
Expand Down Expand Up @@ -286,7 +305,7 @@ fun ColumnChart(
),
size = Size(width = stroke, height = barHeight.absoluteValue.toFloat()),
)
if (rectWithValue.none { it.second == rect }) rectWithValue.add(col.value to rect)
if (barWithRect.none { it.second == rect }) barWithRect.add(col to rect)
val path = Path()

var radius = (col.properties?.cornerRadius ?: barProperties.cornerRadius)
Expand Down Expand Up @@ -348,7 +367,7 @@ private fun DrawScope.drawPopup(
progress: Float,
) {
val measure = textMeasurer.measure(
properties.contentBuilder(selectedBar.value),
properties.contentBuilder(selectedBar.bar.value),
style = properties.textStyle.copy(
color = properties.textStyle.color.copy(
alpha = 1f * progress
Expand All @@ -361,7 +380,7 @@ private fun DrawScope.drawPopup(
width = (textSize.width + (properties.contentHorizontalPadding.toPx() * 2)),
height = textSize.height + properties.contentVerticalPadding.toPx() * 2
)
val value = selectedBar.value
val value = selectedBar.bar.value
val barRect = selectedBar.rect
val barWidth = barRect.right - barRect.left
val barHeight = barRect.bottom - barRect.top
Expand Down Expand Up @@ -395,10 +414,10 @@ private fun DrawScope.drawPopup(
width = popupSize.width * progress
),
),
topRight = if (selectedBar.value < 0 && outOfCanvas) CornerRadius.Zero else cornerRadius,
topLeft = if (selectedBar.value < 0 && !outOfCanvas) CornerRadius.Zero else cornerRadius,
bottomRight = if (selectedBar.value > 0 && outOfCanvas) CornerRadius.Zero else cornerRadius,
bottomLeft = if (selectedBar.value > 0 && !outOfCanvas) CornerRadius.Zero else cornerRadius
topRight = if (value < 0 && outOfCanvas) CornerRadius.Zero else cornerRadius,
topLeft = if (value < 0 && !outOfCanvas) CornerRadius.Zero else cornerRadius,
bottomRight = if (value > 0 && outOfCanvas) CornerRadius.Zero else cornerRadius,
bottomLeft = if (value > 0 && !outOfCanvas) CornerRadius.Zero else cornerRadius
)
)
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,17 +131,10 @@ fun PieChart(
Canvas(modifier = modifier
.pointerInput(Unit) {
detectTapGestures { offset ->
val centerX = size.width / 2
val centerY = size.height / 2
val dx = offset.x - centerX
val dy = offset.y - centerY
atan2(dy.toDouble(), dx.toDouble()).toDegrees().toFloat().also {
println("degree: $it")
}
pieces
.firstOrNull { it.second.contains(offset) }
?.let {
val (id, rect) = it
val (id, _) = it
details.find { it.id == id }
?.let {
onPieClick(it.pie)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
Expand Down Expand Up @@ -69,6 +70,8 @@ fun RowChart(
modifier: Modifier = Modifier,
data: List<Bars>,
barProperties: BarProperties = BarProperties(),
onBarClick:((Bars.Data)->Unit)? = null,
onBarLongClick:((Bars.Data)->Unit)? = null,
labelProperties: LabelProperties = LabelProperties(
enabled = true,
textStyle = TextStyle.Default
Expand Down Expand Up @@ -117,8 +120,8 @@ fun RowChart(
}.average().toFloat()
}

val rectWithValue = remember {
mutableStateListOf<Pair<Double, Rect>>()
val barWithRect = remember {
mutableStateListOf<Pair<Bars.Data, Rect>>()
}

val selectedBar = remember {
Expand Down Expand Up @@ -186,16 +189,16 @@ fun RowChart(
.pointerInput(Unit) {
if (!popupProperties.enabled) return@pointerInput
detectDragGestures { change, dragAmount ->
rectWithValue
.lastOrNull { (value, rect) ->
barWithRect
.lastOrNull { (bar, rect) ->
change.position.y in rect.top..rect.bottom
}
?.let { (value, rect) ->
?.let { (bar, rect) ->
selectedBar.value = SelectedBar(
value = value,
bar = bar,
rect = rect,
offset = Offset(
x = if (value > 0) rect.right else rect.left,
x = if (bar.value > 0) rect.right else rect.left,
y = rect.top
)
)
Expand All @@ -210,28 +213,50 @@ fun RowChart(
}
}
}
.pointerInput(Unit){
detectTapGestures(
onTap = {
val position = Offset(it.x, it.y)
barWithRect
.lastOrNull { (bar,rect)->
rect.contains(position)
}
?.let { (bar, rect) ->
if (popupProperties.enabled){
selectedBar.value = SelectedBar(
bar = bar,
rect = rect,
offset = Offset(
x = if (bar.value > 0) rect.right else rect.left,
y = rect.top
)
)
scope.launch {
popupAnimation.snapTo(0f)
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
)
}
}
onBarClick?.invoke(bar)
}
},
onLongPress = {
val position = Offset(it.x, it.y)
barWithRect
.lastOrNull { (bar,rect)->
rect.contains(position)
}
?.let { (bar, rect) ->
onBarLongClick?.invoke(bar)
}
}
)
}
.pointerInteropFilter { event ->
if (event.action == MotionEvent.ACTION_DOWN && popupProperties.enabled) {
val position = Offset(event.x, event.y)
rectWithValue
.lastOrNull { it.second.contains(position) }
?.let { (value, rect) ->
selectedBar.value = SelectedBar(
value = value,
rect = rect,
offset = Offset(
x = if (value > 0) rect.right else rect.left,
y = rect.top
)
)
scope.launch {
popupAnimation.snapTo(0f)
popupAnimation.animateTo(
1f,
animationSpec = popupProperties.animationSpec
)
}
}

}
false
}) {
Expand Down Expand Up @@ -278,7 +303,7 @@ fun RowChart(

val path = Path()

if (rectWithValue.none { it.second == rect }) rectWithValue.add(bar.value to rect)
if (barWithRect.none { it.second == rect }) barWithRect.add(bar to rect)

var radius = (bar.properties?.cornerRadius ?: barProperties.cornerRadius)
if (bar.value < 0) {
Expand Down Expand Up @@ -340,7 +365,7 @@ private fun DrawScope.drawPopUp(
progress: Float,
) {
val measure = textMeasurer.measure(
properties.contentBuilder(selectedBar.value),
properties.contentBuilder(selectedBar.bar.value),
style = properties.textStyle.copy(
color = properties.textStyle.color.copy(
alpha = 1f * progress
Expand All @@ -352,7 +377,7 @@ private fun DrawScope.drawPopUp(
width = (textSize.width + (properties.contentHorizontalPadding.toPx() * 2)),
height = textSize.height + properties.contentVerticalPadding.toPx() * 2
)
val value = selectedBar.value
val value = selectedBar.bar.value
val barRect = selectedBar.rect
val barHeight = barRect.bottom - barRect.top
val barWidth = barRect.right - barRect.left
Expand Down
Loading

0 comments on commit 1ed207c

Please sign in to comment.