2

Currently it takes around 4-5 seconds to update the product images when you click on a color swatch in Magento 2. Example:

https://youtu.be/AeOTEth4TOc

How can you improve this performance?

It seems all the image information is already available in the jsonConfig object, so it shouldn't take this long even when you're in developer mode.

4
  • Can you try to do all steps described in magento.stackexchange.com/questions/125979/… and try one more time?
    – KAndy
    Jul 21, 2016 at 5:45
  • @KAndy how long does it take for you to change colors on /caesar-warm-up-pant.html in developer mode? (It would be better if I can increase the performance in developer mode since that's the mode I'm in when developing.)
    – thdoan
    Jul 21, 2016 at 7:07
  • For me it 0.3 sec. But it looks for me as a bug, so please create issue on github
    – KAndy
    Jul 21, 2016 at 13:30
  • @KAndy it was reported in issue #5655.
    – thdoan
    Jul 22, 2016 at 2:52

2 Answers 2

1
for magento 2.1.0

<div class="swatch-opt" data-role="swatch-options"></div>
<script>
    require(["jquery", "jquery/ui", "Magento_Swatches/js/swatch-renderer"], function ($) {
        var oJsonConfig = <?php echo $block->getJsonConfig(); ?>;
        $('.swatch-opt').SwatchRenderer({                    
            jsonConfig: <?php /* @escapeNotVerified */ echo $block->getJsonConfig(); ?>,
            jsonSwatchConfig: <?php /* @escapeNotVerified */ echo $block->getJsonSwatchConfig(); ?>,
            mediaCallback: '<?php /* @escapeNotVerified */ echo $block->getMediaCallback() ?>'
        });
    $('[data-gallery-role=gallery-placeholder]').on('gallery:loaded', function() {
    // NOTE: Using .one() instead of .on() to prevent duplicate bindings.
    $('.fotorama').one('fotorama:ready', function(e, fotorama, extra) {
      // Update product images faster when clicking on color swatch
      $('.swatch-option.color').click(function() {        
        var sOptionId = this.getAttribute('option-id');
        for (var attributeId in oJsonConfig.attributes) {
          console.log(oJsonConfig);
          var oAttribute = oJsonConfig.attributes[attributeId];
          if (oAttribute.code==='color') {
            for (var i=0; i<oAttribute.options.length; ++i) {
              var oOption = oAttribute.options[i];
              if (oOption.id===sOptionId) {
                // Gather images
                var aImages = oJsonConfig.images[oOption.products[0]],
                  aFotoramaImages = [];
                for (var j=0; j<aImages.length; ++j) {
                  if (aImages[j].isMain) {
                    // Main image (first position)
                    aFotoramaImages[0] = {
                      full: aImages[j].full,
                      img: aImages[j].img,
                      thumb: aImages[j].thumb
                    };
                  } else {
                    // Subsequent images
                    aFotoramaImages[aImages[j].position] = {
                      full: aImages[j].full,
                      img: aImages[j].img,
                      thumb: aImages[j].thumb
                    };
                  }
                }
                // Load images into Fotorama
                // API reference: http://fotorama.io/customize/api/
                fotorama.load(aFotoramaImages);
                break;
              }
            }
            break;
          }
        }
      });

    });
  });
});
</script>
1

I finally managed to resolve the performance issues and now the product images update almost immediately even in developer mode, so hope the solution below will help others who found themselves in a similar situation. Example after fix:

https://youtu.be/MDpAy_iA3gw

To fix this, first I overrode vendor/magento/module-swatches/view/frontend/templates/product/view/renderer.phtml by copying the file to app/design/frontend/<Vendor>/<theme>/Magento_Swatches/templates/product/view/renderer.phtml.

Then replace the code in this file with this:

<?php /** @var $block \Magento\Swatches\Block\Product\Renderer\Configurable */ ?>
<div class="swatch-opt"></div>
<script>
require(['jquery', 'jquery/ui', 'Magento_Swatches/js/swatch-renderer'], function($) {
  var oJsonConfig = <?php echo $block->getJsonConfig(); ?>;

  $('.swatch-opt').SwatchRenderer({
    jsonConfig: oJsonConfig,
    jsonSwatchConfig: <?php /* @escapeNotVerified */ echo $swatchOptions = $block->getJsonSwatchConfig(); ?>,
    mediaCallback: '<?php /* @escapeNotVerified */ //echo $block->getMediaCallback() ?>'
  });

  // Need to wait for gallery to be loaded before querying $('.fotorama')
  $('[data-gallery-role=gallery-placeholder]').on('gallery:loaded', function() {
    // NOTE: Using .one() instead of .on() to prevent duplicate bindings.
    $('.fotorama').one('fotorama:ready', function(e, fotorama, extra) {

      // Update product images faster when clicking on color swatch
      $('.swatch-option.color').click(function() {
        var sOptionId = this.getAttribute('option-id');
        for (var attributeId in oJsonConfig.attributes) {
          var oAttribute = oJsonConfig.attributes[attributeId];
          if (oAttribute.code==='color') {
            for (var i=0; i<oAttribute.options.length; ++i) {
              var oOption = oAttribute.options[i];
              if (oOption.id===sOptionId) {
                // Gather images
                var aImages = oJsonConfig.images[oOption.products[0]],
                  aFotoramaImages = [];
                for (var j=0; j<aImages.length; ++j) {
                  if (aImages[j].isMain) {
                    // Main image (first position)
                    aFotoramaImages[0] = {
                      full: aImages[j].full,
                      img: aImages[j].img,
                      thumb: aImages[j].thumb
                    };
                  } else {
                    // Subsequent images
                    aFotoramaImages[aImages[j].position] = {
                      full: aImages[j].full,
                      img: aImages[j].img,
                      thumb: aImages[j].thumb
                    };
                  }
                }
                // Load images into Fotorama
                // API reference: http://fotorama.io/customize/api/
                fotorama.load(aFotoramaImages);
                break;
              }
            }
            break;
          }
        }
      });

    });
  });
});
</script>

Hopefully my comments are sufficient to understand what's going on, but here are some notes that might not be obvious at first:

  • I moved jsonConfig one scope up to the variable oJsonConfig in order to access it outside .SwatchRenderer(). This object contains all the image data we need to update the Fotorama plugin when the user selects a color swatch.
  • The color swatch click handler needs to be attached using .one() instead of .on() to prevent adding the same event handler again whenever Fotorama is loaded with new images. I'm pretty sure you can also choose to move the click handler declaration outside of fotorama:ready and use .on() instead.
  • The statement echo $block->getMediaCallback() was commented out since the default callback interferes with our new click handler.
6
  • Just to tell you that you solved my problem with your solution, though there is a small touchup needed require(['jquery', 'jquery/ui', 'swatchRenderer'], should be replaced by require(['jquery', 'jquery/ui', "Magento_Swatches/js/swatch-renderer"],.
    – Memes
    Oct 11, 2016 at 10:16
  • Yeah, thanks for pointing that out. After upgrading from 2.0 to 2.1.1 swatchRenderer needs to be replaced with Magento_Swatches/js/swatch-renderer. I'll update the solution.
    – thdoan
    Oct 12, 2016 at 3:27
  • @10basetom If I use custom slider to display product images then how to replace swatches images ? May 23, 2017 at 6:01
  • @RonakChauhan it will depend on the slider plugin. Most should have the ability to refresh or update the slides by passing in an object or array of images.
    – thdoan
    May 23, 2017 at 9:02
  • magento.stackexchange.com/questions/175627/… check this question. I am using slick slider @10basetom May 23, 2017 at 9:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.