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

Get stencil coordinates after change & auto-zoom #109

Closed Dylan190774 closed 3 years ago

Dylan190774 commented 3 years ago

I have a Cropper with auto-zoom set to true. I wish to get the absolute coordinates of the stencil, after something has changed.

To do this I do something like this in the v-on:change event:

    let stencil = document.querySelector(".vue-rectangle-stencil");
    let stencil_rect = stencil.getBoundingClientRect();

With that I 'm able do what I want (overlay the stencil with some stuff). This works fine while dragging the handles, but after I release a handle, because of the auto-zoom, the stencil is moved to the center and resized. But it doesn't trigger a change-event anymore after that, so I'm not able to update my overlay with the new coordinates.

Any way to trigger some event after the auto-zoom has finished ?

Norserium commented 3 years ago

Hello, @Dylan190774!

I'm wondering why do you need to get absolute coordinates of the stencil?

To answer your question, there is no such feature now. To be clear, auto-zoom changes the coordinates immediately and the smooth animation of resizing is the result of using transitions. I have some plans about adding transition-end and transition-start events that would be helpful in this case with some limitations, but I'm not sure that they will be implemented soon.

Anyway, there are workarounds to solve your problem (they're workarounds, so use them carefully). For example, you can calculate the relative coordinates of the stencil yourself. It will give you pretty precise result.

const cropper = this.$refs.cropper;
if (cropper) {
    const cropperCoordinates = cropper.$el.getBoundingClientRect();
    const stencilCoordinates = cropper.stencilCoordinates;
    const left = cropperCoordinates.left + stencilCoordinates.left;
    const top = cropperCoordinates.top + stencilCoordinates.top;
}
Dylan190774 commented 3 years ago

I understand that this can be used to calculate the coordinates, but the problem was when to do this. Somehow it needs to be triggered when the transition has ended. A transition-end event would be great :)

A slotin the cropper (or stencil) component would als be nice, so I could use this to put the overlay in, but I understand that's even more complicated :)

Norserium commented 3 years ago

Could you explain why do you need to get the coordinates? Why do you need to put overlay in? Because there is the overlay right now. I suppose there is another way to implement what you want to get, I just need to know what it is.

Dylan190774 commented 3 years ago

I'm making some kind of graphics editor that can turn a picture into a mosaic. It would be nice to display the calculated mosaic directly onto the editor, without switching to another page/tab.

See this page for examples of what I'm trying to do: http://close-pixelate.desandro.com/

Dylan190774 commented 3 years ago

I added the following to achieve what I want:

     let that = this;
     const cropper = document.querySelector('.cropper');
     cropper.addEventListener('transitionend', () => {
         that.cropper_update();
     });

In the cropper_updatemethod I redraw the overlay. This works when I use the handles to resize the stencil, but somehow it doesn't work right when I move the stencil, because it doesn't always catch the latest position (it's a few pixels off). Also the transitionendevent is fired multiple times during resizing or moving, which of course slows down the process.

I realize now that maybe a custom stencil-component is the way to go, but this would either need to have access to the cropped image (to be able to calculate the mosaic), or should somehow send an event to the vue-file where I use the cropper to redraw the mosaic. I'm not sure how to do that yet.

Norserium commented 3 years ago

I'm making some kind of graphics editor that can turn a picture into a mosaic. It would be nice to display the calculated mosaic directly onto the editor, without switching to another page/tab.

I don't get the idea completely. Do you need to pixelate the whole image? Could you provide some screenshots of the current result?

Dylan190774 commented 3 years ago

I'm still in the beginning stages, so not much to see yet, but I'll keep you posted :)

By the way, the following solution seems to work a lot better than my previous one:

 ,  mounted () {
      let that = this;

      that.$watch(
          () => {
              return that.$refs.cropper.transitionsActive;
          },
        (val) => {
          that.cropper_update();
        }
      )
    }
Norserium commented 3 years ago

I'm still in the beginning stages, so not much to see yet, but I'll keep you posted :)

You could illustrate your idea in a some picture editor. Select by color the areas that should be pixelated and it will answer on my previous question.

Dylan190774 commented 3 years ago

image

Here's the idea of the editor. The overlay is now simply red ;) , but would be the mosaic when it's finished.

This is another example of what such a mosaic could look like when finished:

https://github.com/skiptomyliu/mosaicshapes/blob/master/examples/mosaic3.jpeg

Norserium commented 3 years ago

Now I got it. Thanks.

Norserium commented 3 years ago

@Dylan190774, I suppose that is what you want to get. Yes?

Dylan190774 commented 3 years ago

Wow, that's absolutely fantastic. Great work! This is exactly the idea that I have in mind.

Norserium commented 3 years ago

You are welcome! And keep in mind two things:

  1. It's a still fast made sketch. It may have different disadvantages and limitations. For example, it doesn't support the image rotate / scale (but it's fixable).
  2. I didn't use the close-pixelate library normally. I cat the needed code and transform it to functions, it's much flexible and suitable approach. I suppose it's pretty normal solution, considering the library is 9 years old. It won't be changed.
Dylan190774 commented 3 years ago

I wrote my own version of this library already, so that's ok.

The only thing that bothers me a little bit, is that quite a lot of duplicated code in the new Stencil component is needed to make it work., for example the onMove, onMoveEnd methods, etc. When you'd change the default Stencil, these changes would have to be made in the custom Stencil too.

So it'd still be great if an event was sent by the default Stencil to the Cropper-component when the transition is done. My watchworks, but it's still a little bit fiddly, I think. I'm no expert in Vue communication between components though.

Norserium commented 3 years ago

I suppose that the current solution is the most idiomatic solution for this library. Why? Because the pixelated preview is actually the part of the stencil.

You shouldn't worry about the future changes of default stencil if you don't have plans to create the universal stencil for the community. It's the core feature of this library: creating of your own stencils. Just create the stencil that you need. I will try to assure that breaking changes will appear only in the next major releases.

Dylan190774 commented 3 years ago

Thank you for your effort. The pixelation-logic depends on a lot of different variables (multiple layers, palette, shapes, masks, all kinds of settings, etc.). All this is defined and configured in the main vue-file. What do you think is the best option to pass all this to the stencil? Somehow I still think it's better that the pixelation is done in the vue file than in the cropper or stencil, but I could be wrong :)

Norserium commented 3 years ago

You can pass any props by using stencil-props prop in the cropper.

Norserium commented 3 years ago

I close the issue. Feel free to reopen if necessary.