Coder Social home page Coder Social logo

Comments (6)

Mett-Barr avatar Mett-Barr commented on August 25, 2024

Thank you for your prompt response and assistance. I'd like to provide some updates and clarifications regarding my earlier query:

Callback for Current ZoomableState Updates: It appears that the functionality is already in place within the library. My earlier challenges might have been related to using the Preview mode, but as of now, everything seems to be functioning correctly. This is no longer an issue.

Restricting Zoom and Scroll to X-Axis: I am looking to limit zoom and pan actions strictly to the X-axis, in a manner akin to how graphicsLayer only applies scaleX and translationX, leaving the Y-axis unaffected. Here is an example of what I am aiming for:

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Divider
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.tooling.preview.Preview
import me.saket.telephoto.zoomable.ZoomSpec
import me.saket.telephoto.zoomable.rememberZoomableState
import me.saket.telephoto.zoomable.zoomable
import kotlin.math.sin

@Preview
@Composable
fun ZoomTest() {
    val state = rememberZoomableState(zoomSpec = ZoomSpec(10f))

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.White)
    ) {
        Column(
            Modifier
                .fillMaxSize(0.5f)
                .align(Alignment.Center)
        ) {
            Text("Top Limit")
            Divider()
            SineWave(
                modifier = Modifier
                    .weight(1f)
                    .fillMaxWidth()
                    .zoomable(state, clipToBounds = false)
            )
            Divider()
            Text("Bottom Limit")
            Divider()
            Row(Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.Absolute.SpaceBetween) {
                repeat(5) {
                    Text(text = it.toString())
                }
            }
        }

        Column(modifier = Modifier.align(Alignment.BottomCenter)) {
            Text(
                text = "Zoom rate : x${state.contentTransformation.scale.scaleX}",
                color = Color.Black,
            )
            Text(
                text = "offset x : ${state.contentTransformation.offset.x}",
                color = Color.Black,
            )
            Text(
                text = "offset y : ${state.contentTransformation.offset.y}",
                color = Color.Black,
            )
        }
    }
}

@Composable
fun SineWave(modifier: Modifier) {
    val infiniteTransition = rememberInfiniteTransition(label = "")
    val phaseShift by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 2f * Math.PI.toFloat(),
        animationSpec = infiniteRepeatable(
            animation = tween(durationMillis = 2000, easing = LinearEasing),
            repeatMode = RepeatMode.Restart
        ), label = ""
    )

    Canvas(
        modifier = modifier
    ) {
        val amplitude = size.height / 2
        val frequency = 0.05f
        val strokeWidth = 5f

        var previousPoint = Offset(0f, size.height / 2)

        for (x in 1..size.width.toInt()) {
            val y = size.height / 2 + amplitude * sin(frequency * x + phaseShift)
            val currentPoint = Offset(x.toFloat(), y)
            drawLine(
                color = Color.Blue,
                start = previousPoint,
                end = currentPoint,
                strokeWidth = strokeWidth,
                cap = StrokeCap.Round
            )
            previousPoint = currentPoint
        }
    }
}

Demo : https://youtube.com/shorts/DyyTLcdGzS0?feature=share

If there are any issues in executing this code, I will organize a simple project on GitHub to demonstrate it more clearly.

Thank you for your attention to these matters.

from telephoto.

saket avatar saket commented on August 25, 2024

@Mett-Barr did you mean to post this to #59?

from telephoto.

Mett-Barr avatar Mett-Barr commented on August 25, 2024

@Mett-Barr did you mean to post this to #59?

Sorry, I replied in the wrong place.

from telephoto.

Mett-Barr avatar Mett-Barr commented on August 25, 2024

@burntcookie90

In response to the onClickOutside feature for a zoomable image, it seems to me that the requirement itself falls outside the scope of the Zoomable API. This is because the action to be taken when clicking outside is inherently external to the functionalities of the Zoomable API. Incorporating this capability directly into the Zoomable API could potentially violate the Single Responsibility Principle (SRP), suggesting that it might not be the best approach to include it within the API.

A more fitting solution could be to use a combination of other components, like using a container with clickable and padding properties. This would effectively handle the onClickOutside behavior without overloading the Zoomable API with responsibilities beyond its intended purpose. Such an approach maintains a cleaner separation of concerns and aligns more closely with SRP.
Like this:

    Box(modifier = Modifier.clickable { /* onClickOutside */ }.padding(10.dp)) {
        YourZoomableImage()
    }

from telephoto.

saket avatar saket commented on August 25, 2024

@Mett-Barr unfortunately, that doesn't work for full sized images where clicks received outside the visual edges of an image will get intercepted by telephoto. You could work around this by using Modifier.wrapContent(), but it's not great either as it'll prevent you from making gestures outside the image bounds.

from telephoto.

saket avatar saket commented on August 25, 2024

Addressed by 0347c53.

/**
* The visual bounds of the content, calculated by applying the scale and translation of pan and zoom
* gestures to the value given to [ZoomableState.setContentLocation]. Useful for drawing decorations
* around the content or performing hit tests.
*
* Because [ZoomableState.setContentLocation] can only be called asynchronously, this may be one frame
* behind the UI.
*/
val transformedContentBounds: Rect

Usage:

implementation("me.saket.telephoto:zoomable-image-coil:0.8.0-SNAPSHOT")
val state = rememberZoomableImageState()

Zoomable*Image(
  modifier = Modifier.fillMaxSize(),
  state = state,
  onClick = { offset -> 
    val wasClickedOutside = offset !in state.zoomableState.transformedContentBounds
  },
  …
)

from telephoto.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.