Search code examples
javascriptjqueryhtmlcssaspect-ratio

Dynamic aspect ratio with changing SRC


My problem is that after selecting an initial image file and trying to select another, the aspect ratio does not change in relation to selected image but keeps the aspect ratio of the image selected first.

I want the aspect ratio to dynamically change in relation the the natural aspect ratio of the selected image. I can't figure out a way to fix it without losing the resizable part.

var test = document.getElementById('test');
var draggable = document.getElementById('draggable');
var resizable = document.getElementById('resizable');
var img = document.querySelector('img');

img.onload = function() {
  $(function() {
    $("#draggable").draggable({});
    $("#resizable").resizable({
      aspectRatio: img.naturalWidth / img.naturalHeight,
      maxHeight: 200,
      maxWidth: 200,
      minHeight: 20,
      minWidth: 20,
    });
  });
}

window.addEventListener('load', function() {
  document.querySelector('input[type="file"]').addEventListener('change', function() {
    if (this.files && this.files[0]) {
      img.src = URL.createObjectURL(this.files[0]);
    }
  });
});
#draggable {
  display: inline-block;
  margin: 0px;
}

#resizable {
  position: absolute;
  cursor: move;
  margin: 0px;
  max-height: 200px;
  max-width: 200px;
  box-sizing: border-box;
  border: none;
}

.test {
  width: 300px;
  height: 300px;
  overflow: hidden;
  background-color: beige;
}
<link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/cupertino/jquery-ui.css" rel="stylesheet" />
<link href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>

<input type='file' />

<div id='test' class='test'>
  <div id='draggable' class="ui-widget-content">
    <img id="resizable" class="ui-widget-content">
  </div>
</div>


Solution

  • The issue is because the resizable widget only reads the dimensions of the content when it's instantiated, not when that content changes.

    To fix this you need to check if the resizable widget has already been instantiated on the element and destroy it, along with removing any inline styling which the widget added to the element. Then you can change the image and reinitialise the widget again.

    Also note that if you're using jQuery for the dragging and resizing, it would make sense to make the most of the convenience it offers for selecting the elements in the DOM and adding event handlers, too. Try this:

    $(function() {
      var $draggable = $('#draggable');
      var $resizable = $('#resizable');
    
      $('input[type="file"]').on('change', function() { 
        if (this.files && this.files[0]) {
          var reader = new FileReader();
          reader.onload = function(e) {
            $draggable.draggable();
            
            if ($resizable.hasClass('ui-resizable'))
              $resizable.resizable('destroy').removeAttr('style');
              
            $resizable.prop('src', e.target.result).resizable({
              maxHeight: 200,
              maxWidth: 200,
              minHeight: 20,
              minWidth: 20,
            });
          }
          reader.readAsDataURL(this.files[0]);
        }
      });
    });
    #draggable {
      display: inline-block;
      margin: 0px;
    }
    
    #resizable {
      position: absolute;
      cursor: move;
      margin: 0px;
      max-height: 200px;
      max-width: 200px;
      box-sizing: border-box;
      border: none;
    }
    
    .test {
      width: 300px;
      height: 300px;
      overflow: hidden;
      background-color: beige;
    }
    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.6/themes/cupertino/jquery-ui.css" rel="stylesheet" />
    <link href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    
    <input type='file' />
    <div id='test' class='test'>
      <div id='draggable' class="ui-widget-content">
        <img id="resizable" class="ui-widget-content">
      </div>
    </div>