@@ -19,26 +19,27 @@ import androidx.compose.runtime.saveable.rememberSaveable
19
19
import androidx.compose.ui.Modifier
20
20
import androidx.compose.ui.geometry.Size
21
21
import androidx.compose.ui.graphics.Color
22
+ import androidx.compose.ui.graphics.NativeCanvas
22
23
import androidx.compose.ui.graphics.nativeCanvas
23
24
import androidx.compose.ui.graphics.toArgb
24
25
import androidx.compose.ui.input.pointer.pointerInput
25
26
import androidx.compose.ui.platform.LocalContext
26
27
import androidx.compose.ui.semantics.contentDescription
27
28
import androidx.compose.ui.semantics.semantics
28
29
import androidx.compose.ui.unit.dp
30
+ import co.yml.charts.common.components.accessibility.AccessibilityBottomSheetDialog
31
+ import co.yml.charts.common.components.accessibility.SliceInfo
32
+ import co.yml.charts.common.extensions.collectIsTalkbackEnabledAsState
33
+ import co.yml.charts.common.model.PlotType
34
+ import co.yml.charts.ui.piechart.PieChartConstants.NO_SELECTED_SLICE
29
35
import co.yml.charts.ui.piechart.models.PieChartConfig
30
36
import co.yml.charts.ui.piechart.models.PieChartData
31
37
import co.yml.charts.ui.piechart.utils.convertTouchEventPointToAngle
32
38
import co.yml.charts.ui.piechart.utils.proportion
33
39
import co.yml.charts.ui.piechart.utils.sweepAngles
34
- import co.yml.charts.common.components.accessibility.AccessibilityBottomSheetDialog
35
- import co.yml.charts.common.components.accessibility.SliceInfo
36
- import co.yml.charts.common.extensions.collectIsTalkbackEnabledAsState
37
- import co.yml.charts.common.model.PlotType
38
40
import kotlinx.coroutines.launch
39
41
import kotlin.math.roundToInt
40
42
41
-
42
43
/* *
43
44
* Compose function for Drawing Donut chart
44
45
* @param modifier : All modifier related property
@@ -71,7 +72,7 @@ fun DonutPieChart(
71
72
}
72
73
73
74
var activePie by rememberSaveable {
74
- mutableStateOf(- 1 )
75
+ mutableStateOf(NO_SELECTED_SLICE )
75
76
}
76
77
val accessibilitySheetState =
77
78
rememberModalBottomSheetState(initialValue = ModalBottomSheetValue .Hidden )
@@ -89,9 +90,9 @@ fun DonutPieChart(
89
90
Surface (
90
91
modifier = modifier
91
92
) {
92
- BoxWithConstraints (
93
- modifier = modifier
94
- .aspectRatio(1f )
93
+ val boxModifier = if (pieChartConfig.isClickOnSliceEnabled) {
94
+ modifier
95
+ .aspectRatio(ratio = 1f )
95
96
.background(pieChartConfig.backgroundColor)
96
97
.semantics {
97
98
contentDescription = pieChartConfig.accessibilityConfig.chartDescription
@@ -102,7 +103,17 @@ fun DonutPieChart(
102
103
accessibilitySheetState.show()
103
104
}
104
105
}
105
- }) {
106
+ }
107
+ } else {
108
+ modifier
109
+ .aspectRatio(1f )
110
+ .semantics {
111
+ contentDescription = pieChartConfig.accessibilityConfig.chartDescription
112
+ }
113
+ }
114
+ BoxWithConstraints (
115
+ modifier = boxModifier
116
+ ) {
106
117
107
118
val sideSize = Integer .min(constraints.maxWidth, constraints.maxHeight)
108
119
val padding = (sideSize * pieChartConfig.chartPadding) / 100f
@@ -120,12 +131,11 @@ fun DonutPieChart(
120
131
}
121
132
}
122
133
123
- Canvas (
124
- modifier = Modifier
134
+ val canvasModifier = if (pieChartConfig.isClickOnSliceEnabled) {
135
+ Modifier
125
136
.width(sideSize.dp)
126
137
.height(sideSize.dp)
127
138
.pointerInput(true ) {
128
-
129
139
detectTapGestures {
130
140
val clickedAngle = convertTouchEventPointToAngle(
131
141
sideSize.toFloat(),
@@ -135,14 +145,23 @@ fun DonutPieChart(
135
145
)
136
146
progressSize.forEachIndexed { index, item ->
137
147
if (clickedAngle <= item) {
138
- if (activePie != index)
139
- activePie = index
148
+ activePie = if (activePie != index)
149
+ index
150
+ else
151
+ NO_SELECTED_SLICE
140
152
onSliceClick(pieChartData.slices[index])
141
153
return @detectTapGestures
142
154
}
143
155
}
144
156
}
145
157
}
158
+ } else {
159
+ Modifier
160
+ .width(sideSize.dp)
161
+ .height(sideSize.dp)
162
+ }
163
+ Canvas (
164
+ modifier = canvasModifier
146
165
147
166
) {
148
167
@@ -163,22 +182,54 @@ fun DonutPieChart(
163
182
)
164
183
sAngle + = arcProgress
165
184
}
166
-
167
- if (activePie != - 1 && pieChartConfig.percentVisible)
168
- drawContext.canvas.nativeCanvas.apply {
169
- val fontSize = pieChartConfig.percentageFontSize.toPx()
170
- drawText(
171
- " ${proportions[activePie].roundToInt()} %" ,
172
- (sideSize / 2 ) + fontSize / 4 , (sideSize / 2 ) + fontSize / 3 ,
173
- Paint ().apply {
174
- color = pieChartConfig.percentColor.toArgb()
175
- textSize = fontSize
176
- textAlign = Paint .Align .CENTER
177
- typeface = pieChartConfig.percentageTypeface
178
-
185
+ when {
186
+ activePie != - 1 && pieChartConfig.labelVisible -> {
187
+ val selectedSlice = pieChartData.slices[activePie]
188
+ drawContext.canvas.nativeCanvas.apply {
189
+ val fontSize = pieChartConfig.labelFontSize.toPx()
190
+ var isValue = false
191
+ val textToDraw = when (pieChartConfig.labelType) {
192
+ PieChartConfig .LabelType .PERCENTAGE -> " ${
193
+ proportions[activePie].roundToInt()
194
+ } %"
195
+ PieChartConfig .LabelType .VALUE -> {
196
+ isValue = true
197
+ selectedSlice.value.toString()
198
+ }
199
+ }
200
+ val labelColor = when (pieChartConfig.labelColorType) {
201
+ PieChartConfig .LabelColorType .SPECIFIED_COLOR -> pieChartConfig.labelColor
202
+ PieChartConfig .LabelColorType .SLICE_COLOR -> selectedSlice.color
179
203
}
180
- )
204
+ val shouldShowUnit = isValue && pieChartConfig.sumUnit.isNotEmpty()
205
+ drawLabel(
206
+ canvas = this ,
207
+ pieChartConfig = pieChartConfig,
208
+ labelColor = labelColor,
209
+ shouldShowUnit = shouldShowUnit,
210
+ fontSize = fontSize,
211
+ textToDraw = textToDraw,
212
+ sideSize = sideSize
213
+ )
214
+ }
181
215
}
216
+ activePie == - 1 && pieChartConfig.isSumVisible -> {
217
+ drawContext.canvas.nativeCanvas.apply {
218
+ val fontSize = pieChartConfig.labelFontSize.toPx()
219
+ val textToDraw = " $sumOfValues "
220
+ drawLabel(
221
+ canvas = this ,
222
+ pieChartConfig = pieChartConfig,
223
+ labelColor = pieChartConfig.labelColor,
224
+ shouldShowUnit = pieChartConfig.sumUnit.isNotEmpty(),
225
+ fontSize = fontSize,
226
+ textToDraw = textToDraw,
227
+ sideSize = sideSize
228
+ )
229
+ }
230
+ }
231
+
232
+ }
182
233
}
183
234
}
184
235
if (isTalkBackEnabled) {
@@ -204,3 +255,36 @@ fun DonutPieChart(
204
255
}
205
256
}
206
257
}
258
+
259
+ private fun drawLabel (
260
+ canvas : NativeCanvas ,
261
+ pieChartConfig : PieChartConfig ,
262
+ labelColor : Color ,
263
+ shouldShowUnit : Boolean ,
264
+ fontSize : Float ,
265
+ textToDraw : String ,
266
+ sideSize : Int
267
+ ) {
268
+ val paint = Paint ().apply {
269
+ color = labelColor.toArgb()
270
+ textSize = fontSize
271
+ textAlign = Paint .Align .CENTER
272
+ typeface = pieChartConfig.labelTypeface
273
+ }
274
+ val x = (sideSize / 2 ).toFloat()
275
+ var y: Float = (sideSize / 2 ).toFloat() + fontSize / 3
276
+ if (shouldShowUnit)
277
+ y - = (paint.fontSpacing / 4 )
278
+ canvas.drawText(
279
+ textToDraw,
280
+ x, y,
281
+ paint
282
+ )
283
+ y + = paint.fontSpacing
284
+ canvas.drawText(
285
+ pieChartConfig.sumUnit,
286
+ x,
287
+ y,
288
+ paint
289
+ )
290
+ }
0 commit comments