advanced-cropper / vue-advanced-cropper

The advanced vue cropper library that gives you opportunity to create your own croppers suited for any website design
https://advanced-cropper.github.io/vue-advanced-cropper/
Other
933 stars 130 forks source link

Vuetify.js slider and Image zoom factor #154

Closed ehernandezColegium closed 2 years ago

ehernandezColegium commented 2 years ago

Hey @Norserium!!

This is my top of components for personal projects, thanks a lot and congrats for this!

I'm currently trying to implement zoom for profile avatar using Slider component from Vuetify. I have set step for slider in 1 to go from 0 to 10 and viceversa to handle zoom factor, and works pressing append and prepend icons. I was trying this example but it doesn't works for me.

cropper.cropper(
          ref="cropper",
          :src="img",
          :canvas="false",
          :stencil-props="{aspectRatio: 1}",
          :default-size="defaultSize",
          @change="change",
          stencil-component="circle-stencil",
          image-restriction="fit-area",
          @ready="ready")
v-slider.mt-5(
          color="secondary"
          track-color="secondary"
          v-model="zoomFactor"
          step="1"
          max="10"
          min="0"
          append-icon="clg-add"
          prepend-icon="clg-minus"
          @click:append="zoomIn"
          @click:prepend="zoomOut"
          @change="setZoom"
          @start="oldZoom")
<script>
export default {
  data () {
    return {
      img: 'image.png',
      zoomFactor: 0,
      oldZoomFactor: 0
    }
  },
  methods: {
    defaultSize ({ imageSize }) {
      return {
        width: Math.min(imageSize.height, imageSize.width),
        height: Math.min(imageSize.height, imageSize.width)
      }
    },
    oldZoom (oldFactor) {
      this.oldZoomFactor = oldFactor
    },
    setZoom () {
      // Extracted from this example: https://github.com/Norserium/vue-advanced-cropper/issues/153, it doesn't works
      const cropper = this.$refs.cropper
      if (cropper) {
        if (cropper.imageSize.height < cropper.imageSize.width) {
          const minHeight = cropper.sizeRestrictions.minHeight
          const imageHeight = cropper.imageSize.height
          // Determine the current absolute zoom and the new absolute zoom
          // to calculate the sought relative zoom value
          cropper.zoom(
            (imageHeight - this.zoom * (imageHeight - minHeight)) /
              (imageHeight - this.oldZoomFactor * (imageHeight - minHeight))
          )
        } else {
          const minWidth = cropper.sizeRestrictions.minWidth
          const imageWidth = cropper.imageSize.width
          cropper.zoom(
            (imageWidth - this.zoom * (imageWidth - minWidth)) /
              (imageWidth - this.oldZoomFactor * (imageWidth - minWidth))
          )
        }
      }
    },
    zoomOut () {
      if (this.zoomFactor > 0) {
        this.$refs.cropper.zoom(0.9)
        this.zoomFactor = (this.zoomFactor - 1) || 0
      }
      console.log(this.zoomFactor)
    },
    zoomIn () {
      if (this.zoomFactor < 10) {
        this.$refs.cropper.zoom(1.1)
        this.zoomFactor = (this.zoomFactor + 1) || 10
      }
      console.log(this.zoomFactor)
    }
  }
}
</script>

The idea is, when user drag slider, avatar pic zooms dynamically according to, using change emit on setZoom method. I was trying another thing with no success:

  setZoom () {
      const diff = this.oldZoomFactor - this.zoomFactor
      const factor = diff < 0 ? 0.9 : diff > 0 ? 1.1 : 0
      const range = Math.abs(diff)

      if (range > 0) {
        for (let i = 0; i < range; i++) {
          setTimeout(() => {
            this.$refs.cropper.zoom(factor)
          }, 200)
        }
      }
    },

Any hints that put me in the right direction? Thanks in advances, awesome work!

Norserium commented 2 years ago

@ehernandezColegium, could you create the codesandbox that reproduces your issue? It will be very helpful.

ehernandezColegium commented 2 years ago

Yeah, sure! Here we go: https://codesandbox.io/s/vuetify-slider-vue-advanced-cropper-hrh9u

In Nuxt, for ex, cropper doesn't want to detect change from v-slider.

Thanks in advances for any help here.

Norserium commented 2 years ago

@ehernandezColegium check this out.

ehernandezColegium commented 2 years ago

@ehernandezColegium check this out.

Just for curiosity: how do you determine which are the correct units to validate and calculating zoom input and zoom value? It's brilliant, and tricky for me at moment until I understand why.

Thanks in advances.

Norserium commented 2 years ago

@ehernandezColegium, I need to clarify what do you mean by "units" here and by "validation" alike?

ehernandezColegium commented 2 years ago

Sorry, I was not clear at all.

Units = sizes and coordinates Validations = The correct way to calculate zoom value and zoom input.

Norserium commented 2 years ago

@ehernandezColegium, I've rewrote the example above, because I forgot that the stencil doesn't have the fixed size as in my twitter-like example. Also I've commented everything.

But I will try to explain the logic additionally here.

The problem is that there is not absolute zoom value in this cropper. Perhaps, in the future I will think out something universal and beautiful, but there is only relative zoom now. It's the sad fact.

Therefore the code in my example should solve two tasks:

  1. It should determine the absolute zoom value based on the current cropper state.
  2. It should determine the relative zoom value, that is the ratio between current visible area size and the desired visible area size.

The first task is accomplished by getAbsoluteZoom function that gets the current absolute zoom for the current cropper state. It's needed to set the correct value of the slider input on a manual resize of an image (by mouse wheel or touch).

The second task is accomplished by getVisibleAreaSize function that transforms the absolute zoom to the corresponding visible area size. The ratio getVisibleAreaSize(previousAbsoluteZoom, cropper) / getVisibleAreaSize(currentAbsoluteZoom, cropper) give the sought relative zoom value. It's needed to relatively zoom a cropper image on slider value change.

ehernandezColegium commented 2 years ago

It's "magical" and understandeable your explanation. Thanks a lot for your kindly help.

Last question: ready event works? Need to know when image is loaded correctly to enable slider for manipulation, but always return undefined. Am I missing something? I have demostrated this in the example.

Norserium commented 2 years ago

@ehernandezColegium, ready event should work. But it hasn't any payload. I've added the event processing in the last example.

ehernandezColegium commented 2 years ago

@Norserium Very grateful for all the help. It would be nice document this code as an example for those who want to use Vuetify or similar components in the package docs. Greetings!