Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request possibility - New Recipe #133

Open
mcshaz opened this issue Mar 11, 2025 · 1 comment
Open

Feature Request possibility - New Recipe #133

mcshaz opened this issue Mar 11, 2025 · 1 comment

Comments

@mcshaz
Copy link

mcshaz commented Mar 11, 2025

Firstly thank you so much for this great library!

I wondered if you wanted to add to the zoomableimage/recipes another potential example where the user can click an image, an icon is overlayed and the position of the icon on the original image (offset in pixels) is recorded. I had this requirement and it took a short while to learn the ZoomableState properties, which would have been easier with an example. If not, please close this issue and at least this will be available for those with similar requirements

The code is (obviously the marker locations state would usually be lifted in a production app, and an image would be passed rather than using a system resource)

@Composable
fun ScrollZoomImage(modifier: Modifier = Modifier) {
    val pointIconOffset = (getSystem().displayMetrics.density).run {
        val iconSize = 24f
        Offset(
            x = this * 0.5f * iconSize,
            y = this * 0.5f * iconSize
        )
        // Material design icons have a 2 dp padding, so if using a 'pin' of some descripition like location_on_24:
       /*
        Offset(
            x = this * 0.5f * iconSize,
            y = (iconSize - 2f) * this
        )
        */
    }
    // marker
    val vector = ImageVector.vectorResource(id = R.drawable.point_scan_24)
    val painter = rememberVectorPainter(image = vector)
    // marker collection
    val markers = remember { mutableStateListOf<Offset>()}
    // zoomableImage
    val zoomableState = rememberZoomableState()

    Box(modifier = modifier.fillMaxWidth(),
            contentAlignment = Alignment.Center) {
        ZoomableAsyncImage(
            model = R.drawable.example_large_image,
            contentDescription = "Large Image Example",
            modifier = Modifier.fillMaxSize(),
            alignment = Alignment.TopCenter,
            state = rememberZoomableImageState(zoomableState),
            onClick = { o ->
                val originalImageClickPos = Offset(
                    x = (o.x - zoomableState.transformedContentBounds.left) * zoomableState.contentTransformation.contentSize.width / zoomableState.transformedContentBounds.width,
                    y = (o.y - zoomableState.transformedContentBounds.top) * zoomableState.contentTransformation.contentSize.height / zoomableState.transformedContentBounds.height,
                )
                markers.add(originalImageClickPos)
            }
        )
        Canvas(modifier = Modifier.fillMaxSize()) {
            val bound = zoomableState.contentTransformation.contentSize.toRect()
            markers.map {
                Offset(
                    x = it.x * zoomableState.transformedContentBounds.width / zoomableState.contentTransformation.contentSize.width + zoomableState.transformedContentBounds.left - pointIconOffset.x,
                    y = it.y * zoomableState.transformedContentBounds.height / zoomableState.contentTransformation.contentSize.height + zoomableState.transformedContentBounds.top - pointIconOffset.y,
                ) }
            .filter { bound.contains(it) }
            .forEach {
                translate(left = it.x, top = it.y) {
                    with(painter) {
                        draw(painter.intrinsicSize)
                    }
                }
            }
        }
    }
}
@saket
Copy link
Owner

saket commented Mar 29, 2025

You're right. Converting coordinates between the image and the viewport coordinate spaces isn't simple. telephoto should make this easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants