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

Default example results to 0 height of component #149

Closed vedmant closed 2 years ago

vedmant commented 2 years ago

Hi, I just used default example, here is my component:

<template>
  <Modal :value="value" content-class="max-w-3xl" @input="$emit('input', false)">
    <div class="p-6 pb-16 m-auto max-w-xs">
      <div class="mb-6 text-xl font-semibold leading-7 text-center text-white">
        {{ $t('Create a new team') }}
      </div>
      <div class="mb-6 aspect-w-1 aspect-h-1">
        <div v-if="file">
          <cropper
            class="cropper"
            :src="file"
            :stencil-props="{
              aspectRatio: 1
            }"
            @change="change"
          />
        </div>
        <div v-else class="flex flex-col justify-center items-center bg-gray-800">
          <Btn color="red" class="mb-6" @click="$refs.file.click()">
            <IconUpload class="mr-2 w-5 h-5 text-black" />
            {{ $t('Upload team avatar') }}
          </Btn>
          <div class="text-sm font-medium leading-5 text-center text-gray-400" style="max-width: 8.5rem;">
            Minimum 600 x 600 JPG, JPEG or PNG
          </div>
          <input ref="file" type="file" style="display: none" accept="image/png, image/jpeg" @change="file = $event.target.files[0]">
        </div>
      </div>
      <InputGroup v-model="form.name" :label="$t('Team Name')" class="mb-10" />
      <Btn color="red" class="justify-center w-full" size="xl" :loading="loading">
        {{ $t('Create Team') }}
      </Btn>
    </div>
  </Modal>
</template>

<script>
import { Cropper } from 'vue-advanced-cropper'
import Modal from '../UI/Modal'
import Btn from '../UI/Btn'
import IconUpload from '../UI/Icons/IconUpload'
import InputGroup from '../UI/InputGroup'
import 'vue-advanced-cropper/dist/style.css'

export default {
  components: { InputGroup, IconUpload, Btn, Modal, Cropper },

  props: {
    value: Boolean,
  },

  data: () => ({
    file: null,
    loading: false,
    form: {
      name: '',
    },
    zoom: 0,
  }),

  methods: {
    change (e) {
      console.log(e)
    },
  },
}
</script>

When I select image cropper has 0 height: Profile 2021-07-20 13-27-45

Norserium commented 2 years ago

@vedmant, the src attribute receives an url to an image, dataURL or blob, not an image file itself.

Take a look at the sandbox example.

vedmant commented 2 years ago

@Norserium I tried blob, but still can't make it work, height is 0. Can it be that initially there is no image selected and I don't show cropper <div v-if="image.src">.

Here is still not working code based on the example:

<template>
  <Modal :value="value" content-class="max-w-3xl" @input="$emit('input', false)">
    <div class="p-6 pb-16 m-auto max-w-xs">
      <div class="mb-6 text-xl font-semibold leading-7 text-center text-white">
        {{ $t('Create a new team') }}
      </div>
      <div class="mb-6 bg-gray-800 aspect-w-1 aspect-h-1">
        <div v-if="image.src">
          <cropper
            ref="cropper"
            class="h-full cropper"
            :src="image.src"
            :stencil-props="{
              aspectRatio: 1
            }"
            @change="change"
          />
        </div>
        <div v-else class="flex flex-col justify-center items-center">
          <Btn color="red" class="mb-6" @click="$refs.file.click()">
            <IconUpload class="mr-2 w-5 h-5 text-black" />
            {{ $t('Upload team avatar') }}
          </Btn>
          <div class="text-sm font-medium leading-5 text-center text-gray-400" style="max-width: 8.5rem;">
            Minimum 600 x 600 JPG, JPEG or PNG
          </div>
          <input ref="file" type="file" style="display: none" accept="image/*" @change="uploadImage">
        </div>
      </div>
      <InputGroup v-model="form.name" :label="$t('Team Name')" class="mb-10" />
      <Btn color="red" class="justify-center w-full" size="xl" :loading="loading">
        {{ $t('Create Team') }}
      </Btn>
    </div>
  </Modal>
</template>

<script>
// import Cropper from 'cropperjs'
import { Cropper } from 'vue-advanced-cropper'
import Modal from '../UI/Modal'
import Btn from '../UI/Btn'
import IconUpload from '../UI/Icons/IconUpload'
import InputGroup from '../UI/InputGroup'
// import 'cropperjs/dist/cropper.css'
import 'vue-advanced-cropper/dist/style.css'

export default {
  components: { InputGroup, IconUpload, Btn, Modal, Cropper },

  props: {
    value: Boolean,
  },

  data: () => ({
    image: {
      src: null,
      type: null,
    },
    loading: false,
    form: {
      name: '',
    },
    zoom: 0,
  }),

  methods: {
    uploadImage (event) {
      /// Reference to the DOM input element
      const { files } = event.target
      // Ensure that you have a file before attempting to read it
      if (files && files[0]) {
        // 1. Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
        if (this.image.src) {
          URL.revokeObjectURL(this.image.src)
        }
        // 2. Create the blob link to the file to optimize performance:
        const blob = URL.createObjectURL(files[0])

        // 3. Update the image. The type will be derived from the extension and it can lead to an incorrect result:
        this.image = {
          src: blob,
          type: files[0].type,
        }
      }
    },

    change ({ coordinates, canvas }) {
      console.log(coordinates, canvas)
    },

    destroyed () {
      // Revoke the object URL, to allow the garbage collector to destroy the uploaded before file
      if (this.image.src) {
        URL.revokeObjectURL(this.image.src)
      }
    },
  },
}
</script>
vedmant commented 2 years ago

Here I have 0 heights in cropper dom: Profile 2021-07-20 14-49-44 But image blob is loaded: Profile 2021-07-20 14-50-32 Weird that there is no errors.

Norserium commented 2 years ago

Can it be that initially there is no image selected and I don't show cropper

It shouldn't be a problem, but you can try to remove it and test the image loading. Also, try to set the fixed height for the cropper itself.

By the way, what's the version of the cropper do you use?

vedmant commented 2 years ago

@Norserium I use "vue-advanced-cropper": "^1.7.0", something weird is happening here, even when I set src to a url:

<Cropper
            ref="cropper"
            class="w-full h-full cropper"
            :stencil-props="{
              aspectRatio: 1
            }"
            src="https://images.pexels.com/photos/4218687/pexels-photo-4218687.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940"
            @change="change"
          />

I see src is null on Cropper component in dev tools: Profile 2021-07-20 15-08-54

Norserium commented 2 years ago

@vedmant, could you sent me the full html code of the fragment?

vedmant commented 2 years ago

@Norserium Do you mean this:

<div class="w-full h-full cropper vue-advanced-cropper"><div class="vue-advanced-cropper__stretcher" style="height: auto; width: auto;"></div> <div class="vue-advanced-cropper__boundaries" style="width: auto; height: auto; transition: opacity 300ms ease 0s; pointer-events: none; opacity: 0;"><div class="vue-advanced-cropper__cropper-wrapper"><div class="vue-advanced-cropper__background" style="width: auto; height: auto; transition: opacity 300ms ease 0s; pointer-events: none; opacity: 0;"></div> <div class="vue-advanced-cropper__image-wrapper"><img class="vue-advanced-cropper__image" style="height: 0px; left: 0px; top: 0px;"></div> <div class="vue-advanced-cropper__foreground" style="width: auto; height: auto; transition: opacity 300ms ease 0s; pointer-events: none; opacity: 0;"></div> <div class="vue-rectangle-stencil vue-rectangle-stencil--movable" style="width: 0px; height: 0px; transform: translate(0px, 0px); display: none;"><div class="vue-bounding-box vue-rectangle-stencil__bounding-box"><div><div class="vue-preview vue-preview--fill vue-rectangle-stencil__preview"><div class="vue-preview__wrapper" style="width: 0px; height: 0px; left: calc(50% - 0px); top: calc(50% - 0px);"><img class="vue-preview__image" style="width: 0px; height: 0px; left: 0px; top: 0px; display: none;"></div></div></div> <div><div class="vue-line-wrapper vue-line-wrapper--east vue-simple-line-wrapper vue-simple-line-wrapper--east"><div class="vue-simple-line vue-simple-line--east"></div></div><div class="vue-line-wrapper vue-line-wrapper--west vue-simple-line-wrapper vue-simple-line-wrapper--west"><div class="vue-simple-line vue-simple-line--west"></div></div><div class="vue-line-wrapper vue-line-wrapper--south vue-simple-line-wrapper vue-simple-line-wrapper--south"><div class="vue-simple-line vue-simple-line--south"></div></div><div class="vue-line-wrapper vue-line-wrapper--north vue-simple-line-wrapper vue-simple-line-wrapper--north"><div class="vue-simple-line vue-simple-line--north"></div></div></div> <div class="vue-bounding-box__handler vue-bounding-box__handler--east-south"><div class="vue-handler-wrapper vue-handler-wrapper--east-south vue-simple-handler-wrapper vue-simple-handler-wrapper--east vue-simple-handler-wrapper--south vue-simple-handler-wrapper--east-south vue-bounding-box__handler vue-bounding-box__handler--east-south"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--east vue-simple-handler--south vue-simple-handler--east-south"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--east-north"><div class="vue-handler-wrapper vue-handler-wrapper--east-north vue-simple-handler-wrapper vue-simple-handler-wrapper--east vue-simple-handler-wrapper--north vue-simple-handler-wrapper--east-north vue-bounding-box__handler vue-bounding-box__handler--east-north"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--east vue-simple-handler--north vue-simple-handler--east-north"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--east"><div class="vue-handler-wrapper vue-handler-wrapper--east vue-simple-handler-wrapper vue-simple-handler-wrapper--east vue-bounding-box__handler vue-bounding-box__handler--east"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--east"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--west-south"><div class="vue-handler-wrapper vue-handler-wrapper--west-south vue-simple-handler-wrapper vue-simple-handler-wrapper--west vue-simple-handler-wrapper--south vue-simple-handler-wrapper--west-south vue-bounding-box__handler vue-bounding-box__handler--west-south"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--west vue-simple-handler--south vue-simple-handler--west-south"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--west-north"><div class="vue-handler-wrapper vue-handler-wrapper--west-north vue-simple-handler-wrapper vue-simple-handler-wrapper--west vue-simple-handler-wrapper--north vue-simple-handler-wrapper--west-north vue-bounding-box__handler vue-bounding-box__handler--west-north"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--west vue-simple-handler--north vue-simple-handler--west-north"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--west"><div class="vue-handler-wrapper vue-handler-wrapper--west vue-simple-handler-wrapper vue-simple-handler-wrapper--west vue-bounding-box__handler vue-bounding-box__handler--west"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--west"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--south"><div class="vue-handler-wrapper vue-handler-wrapper--south vue-simple-handler-wrapper vue-simple-handler-wrapper--south vue-bounding-box__handler vue-bounding-box__handler--south"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--south"></div></div></div></div><div class="vue-bounding-box__handler vue-bounding-box__handler--north"><div class="vue-handler-wrapper vue-handler-wrapper--north vue-simple-handler-wrapper vue-simple-handler-wrapper--north vue-bounding-box__handler vue-bounding-box__handler--north"><div class="vue-handler-wrapper__draggable"><div class="vue-simple-handler vue-simple-handler--north"></div></div></div></div></div></div> <canvas style="display: none;"></canvas> <canvas style="display: none;"></canvas></div></div></div>
Norserium commented 2 years ago

@vedmant yes. Is this code a generated result of this template? It's pretty hard to say, what the problem do you have. You should try to clear your code as much as possible, because I'm sure that the problem somewhere in your code.

To start disable, for example, all your styles; try to move cropper outside the modal window and etc.

Norserium commented 2 years ago

@vedmant, any news?

vedmant commented 2 years ago

@Norserium Hey, sorry, I think it's something related to my project setup, the same components works ok in the fiddle, but I can't find the issue for now, it's hard to debug Vue js internals to see why src prop is not passed. I'll try use other cropper. Thanks for your help, I really appreciate this.

Norserium commented 2 years ago

@vedmant, I have some spare time to look via Team Viewer what's the reason of this issue. So if you ready, write me an email (it's in the profile) with the access details and the convenient time (UTC).

vedmant commented 2 years ago

@Norserium Thanks, I'll send you message!

Norserium commented 2 years ago

@vedmant, notify me here, when you've sent the message.

vedmant commented 2 years ago

@Norserium Hey, I sent an email to you.

Norserium commented 2 years ago

It is somehow related to https://github.com/Norserium/vue-advanced-cropper/issues/51.

I will reopen that issue and close this. @dminchev workaround works, but it's need to investigate why.

Norserium commented 2 years ago

@vedmant there are the details of investigation, just in case.