Generally, you can determine the position of an element(thumb) within a component(slider) by finding the start and the end of the component(slider), then by using a fraction of the current progress of the component, you could use linear interpolation to determine the exact position. Values of offsetStartExtra
and offsetEndExtra
variables are are based on experiments just to get the thumb axies right, you may want to change them to other values based on your padding, thumb size, parent position, etc. If needed, play around with them until you get it rigth within your layout.
Slider (Horizontal):
Notice I calculate the end and the start of the slider on onGloballyPositioned
var sliderValue by remember { mutableStateOf(0f) }
var start by remember { mutableStateOf(Offset.Zero) }
var end by remember { mutableStateOf(Offset.Zero) }
var thumbCoordinates by remember { mutableStateOf(Offset.Zero) }
Box(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
) {
Slider(
value = sliderValue,
onValueChange = { newValue ->
sliderValue = newValue
// updating the thumbCoordinate using linear interpolation
thumbCoordinates = start + (end - start) * (sliderValue / maxSliderValue)
},
valueRange = minSliderValue..maxSliderValue,
modifier = Modifier
.align(Alignment.Center)
.onGloballyPositioned { coordinates ->
// calculating start and end of the slider
val posInRoot = coordinates.positionInRoot()
val offsetStartExtra = Offset(x = -28f, y = 10f)
start = posInRoot + offsetStartExtra
val offsetEndExtra = Offset(x = -83f, 10f)
end = posInRoot.copy(posInRoot.x + coordinates.size.width.toFloat()) + offsetEndExtra
thumbCoordinates=start + (end - start) * (sliderValue/range.endInclusive)
}
)
Canvas(modifier = Modifier.fillMaxSize()) {
// using the calculated coordinates here...
drawRect(color = Color.Red, topLeft = thumbCoordinates, size = Size(24f, 24f))
}
}
Result:

Slider (Vertical)
If you have a vertical slider (check this answer), then you might need to tweak some things for start
and end
variables as well as the offset extras in onGloballyPositioned
modifier.
....
.onGloballyPositioned { coordinates ->
val posInRoot = coordinates.positionInRoot()
val startOffsetExtra = Offset(x = 54f, y = -40f)
start = posInRoot + startOffsetExtra
val endOffsetExtra = Offset(x = 54f, y = 15f)
end = posInRoot.copy(y = posInRoot.y - coordinates.size.width.toFloat()) + endOffsetExtra
}
....
Result

Now for your case, you could draw a line with canvas provding startPoint as position of first thumb, and end point the position of the 2nd thumb, then you could draw another line starting from 2nd thumb and ending on the 3rd. Or you could just draw a path with canvas providing all the thumb's positions.